[ZOJ1015]Fishing Net-弦图判断

Fishing Net

Description

In a highly modernized fishing village, inhabitants there make a living on fishery. Their major tools, fishing nets, are produced and fixed by computer. After catching fishes each time, together with plenty of fishes, they will bring back the shabby fishing nets, which might be full of leaks. Then they have to inspect those nets. If there exist large leaks, they have to repair them before launching out again.

Obviously, the smaller the leaks in the fishing nets are, the more fishes they will catch. So after coming back, those fishermen will input the information of the fishing nets into the computer to check whether the nets have leaks.

The checking principle is very simple: The computer regards each fishing net as a simple graph constructed by nodes and edges. In the graph, if any circle whose length (the number of edges) is larger than 3 must has at least one chord, the computer will output “Perfect” indicating that the fishnet has no leaks. Otherwise, “Imperfect” will be displayed and the computer will try to repair the net.

Note: A circle is a closed loop, which starts from one node, passes through other distinct nodes and back to the starting node. A chord is an edge, which connects two different nodes on the circle, but it does not belong to the set of edges on the circle.

Input

The input file contains several test cases representing different fishing nets. The last test case in the input file is followed by a line containing 0 0.

The first line of each test case contains two integers, n and m, indicating the number of nodes and edges on the net respectively, 1 <= n <= 1000. It is followed by m lines accounting for the details of the edges. Each line consists of two integers xi and yi, indicating there is an edge between node xi and node yi.

Output

For each test case, display its checking results. The word “Imperfect” suggests that the corresponding fishing net is leaking, while the word “Perfect” stands for a fishing net in good condition.

Follow the output for each net with a blank line.

Sample Input

4 4
1 2
2 3
3 4
4 1
3 3
1 2
2 3
3 1
0 0

Sample Output

Imperfect

Perfect


第一次接触弦图这种简(sang)直(xin)巧(bing)妙(kuang)的东西……
一边回想方法一边打,居然一遍就过了~
对于咱这种基本每题都要调好久的蒟蒻来说简直是太难得了o((≧▽≦o)~

思路:
这题还要思路吗(笑)题面都明说了是判断弦图了~
如果不知道弦图是什么的话详见CDQ大触的PPT~

关于做法——最大势算法CDQ大触也已经介绍的很清楚了,咱只简单的口胡几句:

最大势算法用于求图的完美消除序列——一个无向图是弦图当且仅当它有一个完美消除序列。
初始化所有节点的势为0,然后每次取出势最大的节点并为之标号(第几个取出的),并给它的所有相邻节点的势 +1s加1,重复直到所有点被取出。
然而每个图用最大势算法都能得到一个序列╮( ̄▽ ̄”)╭
所以,还要加入判断是否为完美消除序列的步骤。
大概是,对每个点选中所有比它的标号大的点,判断其中标号最小的一个是否与其它选中点都相邻,不是则不是完美消除序列。

实现上,因为时限较宽咱没有用链表存而是每次暴力for循环查找~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

inline int read()
{
    int x=0;
    char ch=getchar();
    while(ch<'0' || '9'<ch)ch=getchar();
    while('0'<=ch && ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x;
}

const int N=1233;

int id[N],label[N];
bool vis[N],g[N][N];

int main()
{
    while(1)
    {
        int n=read(),m=read();
        if(!(n+m))break;


        for(int i=1;i<=n;i++)
        {
            vis[i]=id[i]=label[i]=0;
            for(int j=1;j<=n;j++)
                g[i][j]=0;
        }

        for(int i=1;i<=m;i++)
        {
            int u=read(),v=read();
            g[u][v]=g[v][u]=1;
        }

        for(int i=n;i>=1;i--)
        {
            int now=-1;
            for(int j=1;j<=n;j++)
                if(!vis[j] && (now==-1 || label[j]>label[now]))
                    now=j;

            id[now]=i;
            vis[now]=true;
            for(int j=1;j<=n;j++)
            {
                if(!g[now][j])continue;
                label[j]++;
            }
        }

        memset(vis,0,sizeof(vis));
        bool flag;

        for(int i=1;i<=n;i++)
        {
            int now=-1;
            for(int j=1;j<=n;j++)
            {
                if(!g[i][j] || id[j]<id[i])continue;
                if(now==-1 || id[j]<id[now])
                    now=j;
                vis[j]=true;
            }

            if(now==-1)continue;
            vis[now]=0;

            for(int j=1;j<=n;j++)
            {
                if(!g[now][j] || id[j]<=id[i])continue;
                vis[j]=0;
            }

            flag=1;

            for(int j=1;j<=n;j++)
            {
                if(!g[i][j] || id[j]<id[i])continue;
                if(vis[j])flag=0;
                vis[j]=0;
            }

            if(!flag)break;
        }

        if(!flag)puts("Imperfect\n");
        else puts("Perfect\n");
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值