POJ 3207 Ikki's Story IV - Panda's Trick(2-SAT)

Description
平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,使这些边都不相交。
Input
第一行为两个整数n和m表示点数和边数,之后m行每行两个整数a和b表示a和b要连一条边
Output
如果存在可行方案则输出panda is telling the truth…
否则输出the evil panda is lying again
Sample Input
4 2
0 1
3 2
Sample Output
panda is telling the truth…
Solution
2-SAT判定,以要连的边为节点构图判断可行性。如果第i条边和第j条边有交叉,则有对应限制i->~j ~j->i j->~i ~i->j
接下来只需要用tarjan算法求强联通分量并判断是否存在使得布尔公式值为真的一组布尔变量赋值即可
Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
#define maxn 1111
vector<int>g[maxn];  
stack<int>st;  
int n,m,scc,index;  
int low[maxn],dfn[maxn],instack[maxn],fa[maxn];  
int l[2][maxn];
void init()//初始化 
{  
    scc=index=0;  
    while(!st.empty())st.pop();  
    for(int i=0;i<maxn;i++)g[i].clear();  
    memset(dfn,0,sizeof(dfn));  
    memset(instack,0,sizeof(instack));  
    memset(low,0,sizeof(low));
}  
void tarjan(int u)//求强联通分量 
{  
    dfn[u]=low[u]=++index;  
    instack[u]=1;  
    st.push(u);  
    int v,size=g[u].size();  
    for(int i=0;i<size;i++)  
    {  
        v=g[u][i];  
        if(!dfn[v]) 
        {  
            tarjan(v);  
            low[u]=min(low[u],low[v]);  
        }  
        else if(instack[v]) 
            low[u]=min(low[u],dfn[v]);  
    }  
    if(dfn[u]==low[u])  
    {  
        scc++;  
        do  
        {  
            v=st.top();  
            st.pop();  
            fa[v]=scc;  
            instack[v]=0;  
        }while(v!=u);  
    }  
}  
bool check()//判断可行性 
{
    for(int i=0;i<2*m;i++)//求强联通分量 
        if(!dfn[i])
            tarjan(i);
    for(int i=0;i<2*m;i+=2)
        if(fa[i]==fa[i+1])
            return false;
    return true;
}
int main()
{
    scanf("%d%d",&n,&m);
    init();//初始化 
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&l[0][i],&l[1][i]);
        if(l[0][i]>l[1][i])//保证左节点小于右节点,便于判断两边是否交叉 
            swap(l[0][i],l[1][i]);
        for(int j=0;j<i;j++)//限制条件 
            if(l[0][i]<l[0][j]&&l[0][j]<l[1][i]&&l[1][j]>l[1][i]||l[0][j]<l[0][i]&&l[0][i]<l[1][j]&&l[1][i]>l[1][j])
            {
                g[i<<1].push_back((j<<1)+1);
                g[(j<<1)+1].push_back(i<<1);
                g[j<<1].push_back((i<<1)+1);
                g[(i<<1)+1].push_back(j<<1);
            }
    }
    if(check())//存在可行方案 
        printf("panda is telling the truth...\n");
    else//不存在可行方案 
        printf("the evil panda is lying again\n");
    return 0;
} 

你可能感兴趣的:(POJ 3207 Ikki's Story IV - Panda's Trick(2-SAT))