转:
定义:
无向图中,如果任意边数大于3的环,至少存在一条边连接环中不相邻的某两
个点,则称此图为弦图(Chordal Graph)。
zoj1015的题目:
判断无向图是否为弦图,是则输出Perfect,否则输出Imperfect。
以下是时间复杂度为O(n+m)的算法,n是图的点数,m是图的边数。
第一步:给节点编号
设已编号的节点集合为A,未编号的节点集合为B
开始时A为空,B包含所有节点。
for num=n-1 downto 0 do
{
在B中找节点x,使与x相邻的在A集合中的节点数最多,将x编号为num,
并从B移入A
}
第二步:检查
for num=0 to n-1 do
{
对编号为num的节点x,设所有编号大于num且与x相邻的节点集合为C,
在集合C中找出编号最小的节点y,如果集合C中存在不等于y的节点z,
且y与z间没有边,则此图不是弦图,退出。
}
检查完了,则此图是弦图。
#include <iostream>
#include <cstdio>
#include <limits.h>
#include <memory.h>
using namespace std;
#define MAX 1010
bool g[MAX][MAX];
int label[MAX],temp[MAX],temp2[MAX];
int n,m;
void labeling(){
memset(label,0,sizeof(label));
memset(temp,0,sizeof(temp));
for (int i=n;i>=1;--i)
{
int max=-1,pos=0;
for (int j=1;j<=n;++j)
{
if(!label[j]&&temp[j]>max){//找结点X,使与x相邻的在A集合中的节点数最多
max=temp[j];
pos=j;
}
}
label[pos]=i;//将x编号为num
for (int k=1;k<=n;++k)
{
if(!label[k]&&(g[pos][k]||g[k][pos]))temp[k]++;//将与x相邻的点的和A集合连接的数量加一
}
}
}
bool check(){
labeling();
for (int i=n;i>=1;--i)
{
memset(temp2,0,sizeof(temp2));
int minV=INT_MAX,minPos=0;
for (int j=1;j<=n;++j)
{
if(g[i][j]&&label[j]>label[i])temp2[j]=label[j];//设所有编号大于num且与x相邻的节点集合为C
}
for (int j=1;j<=n;++j)
{
if(temp2[j]&&temp2[j]<minV){//找出编号最小的结点y
minV=temp2[j];
minPos=j;
}
}
for (int j=1;j<=n;++j)
{
if(temp2[j]&&j!=minPos&&!g[minPos][j]&&!g[j][minPos])return false;//判断集合中是否存在如果集合C中存在不等于y的节点z, 且y与z间没有边,则此图不是弦图,退出。
}
}
return true;//检查完了就是弦图
}
int main(){
int i;
while (scanf("%d%d",&n,&m)==2)
{
if(!n&&!m)break;
memset(g,0,sizeof(g));
for (i=0;i<m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
g[u][v]=g[v][u]=1;
}
if(check()){
printf("Perfect\n\n");
}else{
printf("Imperfect\n\n");
}
}
return 0;
}