题意:给定一个图G,判断其是否为弦图。弦图定义:如果每个长度大于3的圈中至少有一条弦。(if any circle whose length (the number of edges) is larger than 3 must has at least one chord)。
思路:最大势(MCS)算法。(参考陈丹琦课件)。从n到1的顺序依次给顶点标号(标号i出现的点为完美消除序列中的第i个),d[i]表示第i个点与多少个已标号点相邻。每次选取d[i]最大的未标号点标号。之后,对得到的序列进行检测,看其是否确实为完美消除序列。方法为设{vi+1,vi+2...vn}中所有与vi相邻的点依次为vj1...vjk,只需判断vj1是否与vj2...vjk相邻即可。下面代码中,s数组存储的是完美消除序列,t[i]数组存储的是第i个节点在完美消除序列中的位置。
#include <stdio.h> #include <string.h> #define N 1005 struct edge{ int y,next; }e[N*N]; int first[N],d[N],visited[N],s[N],t[N]; int n,m,top; void add(int x,int y){ e[top].y = y; e[top].next = first[x]; first[x] = top++; } int test(){ int i,j,min,flag[N]; for(i = 1;i<n;i++){ min = s[n]; memset(flag,0,sizeof(flag)); for(j = first[s[i]];j!=-1;j=e[j].next) if(t[e[j].y] > t[s[i]]){//保证从vi+1...vn的这个范围内找 if(t[e[j].y] < t[min]) min = e[j].y;//找到vj1 flag[e[j].y] = 1;//flag为1的是与vi相邻的点 } flag[min] = 0; for(j = first[min];j!=-1;j=e[j].next)//看看vj1是否与vj2...vjn都相邻 if(flag[e[j].y]) flag[e[j].y]--; for(j = 1;j<=n;j++) if(flag[j]) return 0; } return 1; } int main() { freopen("/Users/MeichenDu/Desktop/mango/he/a.txt", "r", stdin); while(scanf("%d %d",&n,&m) &&n&&m){ int i,j,a,b,now; top = 0; memset(d,0,sizeof(d)); memset(visited,0,sizeof(visited)); memset(first, -1, sizeof(first)); for(i = 0;i<m;i++){ scanf("%d %d",&a,&b); add(a,b),add(b,a); } for(i = n;i>=1;i--){ now = 1; for(j = 2;j<=n;j++) if(!visited[j] && d[j]>d[now]) now = j; s[i] = now; t[now] = i; visited[now] = 1; for(j = first[now];!visited[e[j].y]&&j!=-1;j=e[j].next) d[e[j].y]++; } if(test()) printf("Perfect\n\n"); else printf("Imperfect\n\n"); } return 0; }