Havel-Hakimi定理(握手定理)
由非负整数组成的非增序列s(度序列):d1,d2,…,dn(n>=2,d1>=1)是可图的,当且仅当序列:
s1:d2 – 1,d3 – 1,…,dd1+1 – 1,dd1+2,…,dn
是可图的。序列s1中有n-1个非负整数,s序列中d1后的前d1个度数(即d2~dd1+1)减1后构成s1中的前d1个数。
说白了就是先把第一个点(度数为d1)连线到后面d1个点,保证第一个点度数满足,然后再以此类推考虑后面的点。如果后面所有顶点满足并且度数不多不少(最后不剩,过程中没有度数为负数),即可认为,度序列是可图的。
为什么每一次都要排成非递增序列后再操作?因为这样是最好判断的,最后都成0就可图,中途出现负数就不可图。如果不排成非递增就不好判断了,比如最后0,1,0,1是可图的;0,2,0,2不可图,还有各种最终情况,很难写代码去判断可图不可图。
由同一个可图序列构造出来的图不一定是唯一的。
例题poj1659
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<list> #include<deque> #include<vector> #include<algorithm> #include<stack> #include<queue> #include<cctype> #include<sstream> using namespace std; #define pii pair<int,int> #define LL long long int const double eps=1e-10; const int INF=1000000000; const int maxn=10+3;int ans[maxn][maxn]; int T,n; struct node {int id,de; } x[maxn];bool cmp(node a,node b) {return a.de>b.de; }int main() {//freopen("in1.txt","r",stdin);//freopen("out.txt","w",stdout);scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=0; i<n; i++){scanf("%d",&x[i].de);x[i].id=i+1;}memset(ans,0,sizeof(ans));int tn=n;bool can=1;while(tn>0){sort(x,x+n,cmp);if(x[0].de==0) break;for(int i=1; i<=x[0].de; i++){if(x[i].de>0&&i<n){x[i].de--;ans[x[0].id][x[i].id]=ans[x[i].id][x[0].id]=1;}else{can=false;break;}}if(can==false) break;x[0].de=0;tn--;}if(can==true){puts("YES");for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(j==1) printf("%d",ans[i][j]);else printf(" %d",ans[i][j]);}puts("");}}else puts("NO");if(T>=1) puts("");}//fclose(stdin);//fclose(stdout);return 0; }