\(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);
}