现在的位置: 首页 > 综合 > 正文

[poj 2307]Ikki’s Story IV – Panda’s Trick[2-SAT]

2017年12月13日 ⁄ 综合 ⁄ 共 1577字 ⁄ 字号 评论关闭

题意:

连接圆周上标号 [ 0 .. n-1 ] 的点, 连接线可以放在圆内或圆外,但不能交叉(叠放). 给出点的个数n和相连的边(点对).判断是否可行.

思路:

2-SAT简单版:

将每条连接线看成两个点, 分别表示在圆内, 圆外. 实际中这两个点能且只能取其一.

枚举两根连接线的所有组合情况, 根据连接线所连两点的标号判断二者是否回相交.

若会, 则必然一个在圆内, 一个在圆外. 这两条连接线的状态是绑定的, 据此连线(无向图).

Tarjan求出强连通分量,

枚举每一条连接线, 判断它的两种状态是否在同一个强连通分量中. 若是, 矛盾. 否则可行.

**这最后一步是没有优化的(相对于尚未看懂的<<由对称性解2-SAT问题>>...)

#include <cstdio>
#include <cstring>
#include <stack>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
const int MAXE = 505;
struct pool
{
    int v,pre;
}p[MAXE*MAXE];
int edge[MAXE][2],n,m;
int head[MAXE<<1],num,dfn[MAXE<<1],low[MAXE<<1],id[MAXE<<1],size,Index;
bool used[MAXE<<1];
stack<int> s;

void add(int u, int v)
{
    p[++num].v = v;
    p[num].pre = head[u];
    head[u] = num;
}

void Tarjan(int u)
{
    dfn[u] = low[u] = ++Index;
    used[u] = true;
    s.push(u);
    
    for(int tmp=head[u],k;k=p[tmp].v,tmp;tmp=p[tmp].pre)
    {
        if(!dfn[k])
        {
            Tarjan(k);
            low[u] = min(low[u],low[k]);
        }
        else if(used[k]) low[u] = min(low[u],dfn[k]);
    }
    if(dfn[u] == low[u])
    {
        size++;
        int k;
        do
        {
            k = s.top();s.pop();
            used[k] = false;
            id[k] = size;
        }while(u!=k);
    }
}

int main()
{
    scanf("%d %d",&n,&m);
    for(int i = 0,u,v;i<m;i++)
    {
        scanf("%d %d",&u,&v);
        edge[i][0] = u,edge[i][1] = v;
        if(edge[i][0]>edge[i][1])   swap(edge[i][0],edge[i][1]);
    }
    for(int i=0;i<m;i++)
    {
        for(int j=i+1;j<m;j++)
        {
            if( (edge[i][0]<edge[j][0] && edge[i][1]<edge[j][1] && edge[i][1]>edge[j][0])
            ||  (edge[i][0]>edge[j][0] && edge[i][1]>edge[j][1] && edge[i][1]<edge[j][0])  )
            {
                add(i,j+m);
                add(j,i+m);
                add(i+m,j);
                add(j+m,i);
            }

        }
    }
    for(int i=0;i<m<<1;i++)//每一种状态都要试一遍
    {
        if(!dfn[i])
            Tarjan(i);
    }
    bool flag = true;
    for(int i=0;i<m;i++)
        if(id[i]==id[i+m])
        {
            flag = false;
            //printf("%d and %d\n",edge[i][0],edge[i][1]);
            break;
        }
    if(flag)    printf("panda is telling the truth...\n");
    else        printf("the evil panda is lying again\n");
}

抱歉!评论已关闭.