题意简述:给定一个无向图,判断是否存在一个长度大于3的环路,且其上没有弦(连接环上不同两点的边且不在环上)。
命题等价于该图是否存在完美消除序列。
所谓完美消除序列:在 vi,vi+1,...vn vi与之后与vi相邻的点构成一个团(完全子图)。
求完美消除序列的MCS算法。倒序给点标号,标号为i的点出现在序列的第i项。对每个顶点i,维护标号label[i],表示标号的度,每次选择标号最大的点标号。用堆加速。
求出了完美消除序列后,只要判断这个序列是否合法就可以得出结论。
在 vi,vi+1,...vn的导出子图中找到与vi相邻的标号最小(度最小)的点,设为vj,再检查vj是否与每个vi的邻接点相邻。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<vector> #include<queue> #include<algorithm> #include<set> #define clr(x,y) memset(x,y,sizeof(x)) using namespace std; const int maxn=1010; vector<int> construct(int n,vector<int> adj[maxn]) { static int rank[maxn],label[maxn]; clr(rank,-1);clr(label,0); priority_queue<pair<int,int> > heap; for(int i=1;i<=n;i++) heap.push(make_pair(0,i)); for(int i=n-1;i>=0;i--) { while(true) { int u=heap.top().second;heap.pop(); if(rank[u]==-1) { rank[u]=i; for(vector<int>:: iterator iter=adj[u].begin();iter!=adj[u].end();++iter) { if(rank[*iter]==-1) { label[*iter]++; heap.push(make_pair(label[*iter],*iter)); } } break; } } } vector<int> result(n); for(int i=1;i<=n;i++) { result[rank[i]]=i; } return result; } bool check(int n,vector<int>adj[maxn],vector<int> ord) { static bool mark[maxn]; static int rank[maxn]; for(int i=0;i<n;i++)rank[ord[i]]=i; clr(mark,0); for(int i=0;i<n;i++) { vector<pair<int,int> >tmp; for(vector<int>::iterator iter=adj[ord[i]].begin();iter!=adj[ord[i]].end();++iter) if(!mark[*iter])tmp.push_back(make_pair(rank[*iter],*iter)); sort(tmp.begin(),tmp.end()); if(tmp.size()) { int u=tmp[0].second;set<int> tmpAdj; for(vector<int>::iterator iter=adj[u].begin();iter!=adj[u].end();++iter) { tmpAdj.insert(*iter); } for(int i=1;i<(int)tmp.size();++i) { if(!tmpAdj.count(tmp[i].second))return false; } } mark[ord[i]]=true; } return true; } bool is_chordal(int nodeCount,vector<pair<int,int> >edges) { int n=nodeCount; vector<int>adj[maxn]; for(int i=0;i<=n;i++) adj[i].clear(); for(vector<pair<int,int> >::iterator iter=edges.begin();iter!=edges.end();++iter) { adj[iter->first].push_back(iter->second); adj[iter->second].push_back(iter->first); } return check(n,adj,construct(n,adj)); } int main() { int n,m; while(scanf("%d%d",&n,&m)) { if(n==0&&m==0)return 0; vector<pair<int,int> >ed; for(int i=0;i<m;i++) { int a,b; scanf("%d%d",&a,&b); ed.push_back(make_pair(a,b)); } if(is_chordal(n,ed))printf("Perfect\n\n"); else printf("Imperfect\n\n"); } return 0; }
完美消除序列还有广泛的应用,以后来补充。