zoj 1015 弦图判断

题意:给定一个图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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值