\(Havel-Hakimi\) 定理
學習資料: makenothing博客
判斷給定度序列是否可簡單圖化
可簡單圖化:一個由非負整數組成的有限序列如果是某個無向圖的序列,則稱該序列是可簡單圖化的。
定理描述:
由非負整數組成的有限非遞增序列, \(S=\{d_1,d_2,...,d_n\}\) , 當且僅當 \(S_1=\{d_2-1,d_3-1,...,d_{d_1+1} -1,d_{d_1+2},...,d_n\}\) 也是可圖的, 也就是說, 序列 \(S_1\) 也是由非負整數組成的有限非遞增序列。
判定過程:
- 對當前序列 \(S\) 排序, 使其呈遞減,若首元素為0, 則判斷該序列可簡單圖化, 否則繼續下一步。
- 刪除序列首元素 \(d_1\) ,並使序列之后的 \(d_1\) 個數的值均減 \(1\), 若出現了負數, 則該可判斷該序列是不可簡單圖化, 否則,繼續上一步。
例題:
P3104 [USACO14MAR]Counting Friends G
一句話題意: 給 \(n+1\) 個數,問哪些數滿足刪除它之后所剩下的長度為 \(n\) 的序列可簡單圖化, 輸出這些數的下標。其中 \(1\le n\le500\) .
\(code:\)
//#pragma GCC optimize("-O2")
#include<bits/stdc++.h>
#define reg register
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
struct A{
int v,id;
}a[maxn];
int p[maxn],t[maxn],n;
bool check()
{
int x,st=1,l1,l2,r1,r2,cnt;
while(p[st]>0)
{
x=p[st];
for(int i=st+1;i<=st+x;i++)p[i]--;
if(p[st+x]<0)return 0;
//歸並排序O(n)替換快排O(nlogn)
l1=st+1;l2=st+x+1;cnt=0;
while(l1<=st+x||l2<=n)
{
if(l1<=st+x&&p[l1]>=p[l2]||l2>n)t[++cnt]=p[l1++];
else t[++cnt]=p[l2++];
}
for(int i=1;i<=cnt;i++)p[st+i]=t[i];st++;
// sort(p+st,p+1+n,greater<int>());
}
return 1;
}
vector<int>ans;
int main()
{
scanf("%d",&n);
for(int i=1,v;i<=n+1;i++)
{
scanf("%d",&a[i].v);a[i].id=i;
}
sort(a+1,a+1+n+1,[](A a1,A a2)->bool{return a1.v>a2.v;});
for(int i=1;i<=n+1;i++)
{
for(int j=1,cnt=0;j<=n+1;j++)
{
if(i==j)continue;
p[++cnt]=a[j].v;
}
if(check())ans.push_back(a[i].id);
}
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
for(int u:ans)printf("%d\n",u);
}