ZOJ1015

题意简述:给定一个无向图,判断是否存在一个长度大于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;
}

  完美消除序列还有广泛的应用,以后来补充。

posted on 2017-02-26 15:14  Bingsen  阅读(357)  评论(0编辑  收藏  举报