POJ 1659 Frogs' Neighberhood

    技术2025-06-08  19

    havel定理,根据度序列构图

     

    把序列排成不增序,即d1 >= d2 >= ... >= dn,则D可简单图化当且仅当D' = (d2 - 1, d3 - 1, ... d(d1 + 1) - 1, d(d1 + 2), d(d1 + 3), ... dn)可简单图化。

    实际上就是说:

      1、把D排序

      2、找出度最大的点(设度为d1)

      3、把它和度次大的d1个点之间连边,然后这个点就可以不管了

      4、转到1,直到建出完整的图,或出现负度等明显不合理的情况。

     

     

    给定一个非负整数序列{d1,d2,...dn},若存在一个无向图使得图中各点的度与此序列一一对应,则称此序列可图化。进一步,若图为简单图,则称此序列可简单图化。可图化的判定比较简单:d1+d2+...dn=0(mod2)。关于具体图的构造,我们可以简单地把奇数度的点配对,剩下的全部搞成自环。可简单图化的判定,有一个Havel定理,是说: 我们把序列排成不增序,即d1>=d2>=...>=dn,则d可简单图化当且仅当d'=(d2-1, d3-1, ... d(d1+1)-1, d(d1+2), d(d1+3), ... dn)可简单图化。这个定理写起来麻烦,实际上就是说,我们把d排序以后,找出度最大的点(设度为d1),把它和度次大的d1个点之间连边,然后这个点就可以不管了,一直继续这个过程,直到建出完整的图,或出现负度等明显不合理的情况。定理的简单证明如下:(<=)若d'可简单图化,我们只需把原图中的最大度点和d'中度最大的d1个点连边即可,易得此图必为简单图。(=>)若d可简单图化,设得到的简单图为G。分两种情况考虑:(a)若G中存在边(V1,V2), (V1,V3), ...(V1,V(d1+1)),则把这些边除去得简单图G',于是d'可简单图化为G'(b)若存在点Vi,Vj使得i<j, (V1,Vi)不在G中,但(V1,Vj)在G中。这时,因为di>=dj,必存在k使得(Vi, Vk)在G中但(Vj,Vk)不在G中。这时我们可以令GG=G-{(Vi,Vk),(V1,Vj)}+{(Vk,Vj),(V1,Vi)}。GG的度序列仍为d,我们又回到了情况(a)。

     

    代码:

    #include<iostream> #include<algorithm> using namespace std; const int MAX=11; struct node { int v,deg; }vertex[MAX]; int g[MAX][MAX],u[MAX]; int n; int cmp(const node &a,const node &b) { return a.deg>b.deg; } bool havel() { int i,cnt,j,from,d; for(j=1;j<n;j++) { sort(vertex+1,vertex+1+n,cmp); for(i=1;i<=n;i++) { if(!u[vertex[i].v]) { u[vertex[i].v]=1; break; } } if(n-j<vertex[i].deg)//剩余的顶点数不够 return false; int now=i; from=vertex[i].v; d=vertex[i].deg; if(d<=0) break; for(i=i+1;i<=n;i++) { if(vertex[now].deg<=0)//一开始没有先判断是否当前点的度数是否已经为0,WA了 break; if(!u[vertex[i].v]) { g[from][vertex[i].v]=g[vertex[i].v][from]=1; vertex[now].deg--; if(--vertex[i].deg<0)//度数为负 return false; } } } return true; } int main() { int i,j,total,T; scanf("%d",&T); while(T--) { memset(g,0,sizeof(g)); memset(u,0,sizeof(u)); scanf("%d",&n); for(i=1;i<=n;i++) vertex[i].v=i; total=0; for(i=1;i<=n;i++) { scanf("%d",&vertex[i].deg); total+=vertex[i].deg; } if(total%2==0&&havel())//握手定理及havel定理 { printf("YES/n"); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) printf("%d ",g[i][j]); printf("/n"); } } else printf("NO/n"); printf("/n"); } return 0; }  

    最新回复(0)