poj 3207 Ikki's Story 2-SAT

Description

liympanda, one of Ikki’s friend, likes playing games with Ikki. Today after minesweeping with Ikki and winning so many times, he is tired of such easy games and wants to play another game with Ikki.

liympanda has a magic circle and he puts it on a plane, there are n points on its boundary in circular border: 0, 1, 2, …, n − 1. Evil panda claims that he is connecting m pairs of points. To connect two points, liympanda either places the link entirely inside the circle or entirely outside the circle. Now liympanda tells Ikki no two links touch inside/outside the circle, except on the boundary. He wants Ikki to figure out whether this is possible…

Despaired at the minesweeping game just played, Ikki is totally at a loss, so he decides to write a program to help him.

Input

The input contains exactly one test case.

In the test case there will be a line consisting of of two integers: n and m (n ≤ 1,000, m ≤ 500). The following m lines each contain two integers ai and bi, which denote the endpoints of the ith wire. Every point will have at most one link.

Output

Output a line, either “panda is telling the truth...” or “the evil panda is lying again”.

Sample Input

4 2
0 1
3 2

Sample Output

panda is telling the truth...

//


平面上,一個圓,圓的邊上按順時針放着n個點。現在要連m條邊,比如a,b,那麼a到b可以從平面正面連接,也可以從平面另一面連接。給你的信息中,每個點最多隻會連接的一條邊。問能不能連接這m條邊,使這些邊都不相交。

【解題思路】

每個邊看成2個點:分別表示在正面連接和在反面連接,只能選擇一個。表示爲點i和點i'

如果兩條邊i和j必須一個畫在正面,一個畫在反面,有矛盾,那麼連邊:

i->j’, 表示i畫正面的話,j只能畫反面,即j’

j->i’,同理

i’->j,同理

j’->i,同理



#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100000;
int V,E;//點數(1) 邊數
struct edge//鄰接表
{
    int t,w;//u->t=w;
    int next;
};
int p[maxn];//表頭節點
edge G[maxn];
int l;
void init()
{
    memset(p,-1,sizeof(p));
    l=0;
}
//添加邊
void addedge(int u,int t,int w)//u->t=w;
{
    G[l].w=w;
    G[l].t=t;
    G[l].next=p[u];
    p[u]=l++;
}
//tarjan算法 求有向圖強聯通分量
int dfn[maxn],lowc[maxn];
//dfn[u]節點u搜索的次序編號,lowc[u]u或者u的子樹能夠追溯到的棧中的最早的節點
int belg[maxn];//第i個節點屬於belg[i]個強連通分量
int stck[maxn],stop;//stck棧
int instck[maxn];//第i個節點是否在棧中
int scnt;//強聯通分量
int index;
void dfs(int i)
{
    dfn[i]=lowc[i]=++index;
    instck[i]=1;//節點i入棧
    stck[++stop]=i;
    for(int j=p[i];j!=-1;j=G[j].next)
    {
        int t=G[j].t;
        //更新lowc數組
        if(!dfn[t])//t沒有遍歷過
        {
        dfs(t);
        if(lowc[i]>lowc[t]) lowc[i]=lowc[t];
        }//t是i的祖先節點
        else if(instck[t]&&lowc[i]>dfn[t]) lowc[i]=dfn[t];
    }
    //是強連通分量的根節點
    if(dfn[i]==lowc[i])
    {
    scnt++;
    int t;
    do
    {
        t=stck[stop--];
        instck[t]=0;
        belg[t]=scnt;
        }while(t!=i);
    }
}
int tarjan()
{
    stop=scnt=index=0;
    memset(dfn,0,sizeof(dfn));
    memset(instck,0,sizeof(instck));
    for(int i=1;i<=V;i++)
    {
        if(!dfn[i]) dfs(i);
    }
    return scnt;
}
int e[maxn][2];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2)
    {
        init();V=2*m;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&e[i][0],&e[i][1]);
            if(e[i][0]>e[i][1])
            {
                e[i][0]=e[i][0]^e[i][1];
                e[i][1]=e[i][0]^e[i][1];
                e[i][0]=e[i][0]^e[i][1];
            }
        }
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if((e[i][0]<e[j][0]&&e[i][1]<e[j][1]&&e[i][1]>e[j][0])||(e[i][0]>e[j][0]&&e[i][1]>e[j][1]&&e[i][1]<e[j][0]))
                {
                    addedge(i,j+m,1);
                    addedge(j,i+m,1);
                    addedge(i+m,j,1);
                    addedge(j+m,i,1);
                }
        tarjan();
        bool flag=false;
        for(int i=1;i<=m;i++)
        {
            if(belg[i]==belg[i+m])
            {
                printf("the evil panda is lying again\n");
                flag=true;
                break;
            }
        }
        if(!flag) printf("panda is telling the truth...\n");
    }
}


發佈了743 篇原創文章 · 獲贊 5 · 訪問量 69萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章