2-SAT ( Tarjan )——POJ 3207

  • 题目链接:
    http://poj.org/problem?id=3207

  • 分析:
    一个环上按顺序标上1-N个点,给出M条边,可以从圆外连接,也可以从圆内连接,求连接所有的边是否能够保证都不相交。

  • 题解:
    每条边有两个状态,只能2选一,要么圆外,要么圆内,所以我们以m条边为点建图,若两条边在同一侧会相交,我们就建边。

  • AC代码:

    这里写图片描述

/*************************************************************************
    > File Name: test.cpp
    > Author: Akira 
    > Mail: qaq.febr2.qaq@gmail.com 
 ************************************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <ctime>
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
using namespace std;

#define MaxN 1005
#define MaxM MaxN*10
#define INF 0x3f3f3f3f
#define bug cout<<88888888<<endl;
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)

int n,m;
int Map[MaxN][MaxN];                //邻接矩阵 存图

int low[MaxN];
int dfn[MaxN];

int Stack[MaxN], top;
int inStack[MaxN];
int belong[MaxN];                   //记录强连通分量
int Index, cnt;

void init()
{
    CLR(Map);
    MST(dfn,-1);
    CLR(low);
    CLR(inStack);
    Index = cnt = 1;
    top = 0;
}


void Tarjan(int x)
{
    int i, a;
    low[x] = dfn[x] = Index;                // 刚搜到一个节点时low = dfn
    Index++;
    Stack[++top] = x;                       // 将该节点入栈
    inStack[x] = 1;                         // 将入栈标记设置为1
    for(i = 1; i <= 2*m; i++)                 // 遍历入栈节点的边
    {
        if(!Map[x][i]) continue;            // 如果两点之间没有边,不用管它

        if(dfn[i] == -1)                    // 如果新搜索到的节点是从未被搜索过
        {
            Tarjan(i);                      // 那自然就得搜索这个节点
            low[x]=MIN(low[x], low[i]);     // 回溯的时候改变当前节点的low值
        }
        else if(inStack[i])                 // 如果新搜索到的节点已经被搜索过而且现在在栈中
        {
            low[x] = MIN(low[x], dfn[i]);   // 更新当前节点的low值,这里的意思是两个节点之间有一条可达边,
        }                                   // 而前面节点已经在栈中,那么后面的节点就可能和前面的节点在一个联通分量中
    }

    if(low[x] == dfn[x])                    // 最终退回来的时候 low == dfn , 没有节点能将根节点更新,那
    {                                       // low == dfn 的节点必然就是根节点
        int temp;
        while(1)                            // 一直出栈到此节点, 这些元素是一个强联通分量
        {
            temp = Stack[top--];            // 弹出栈元素
            belong[temp] = cnt;             // 为了方便计算,将强联通分量进行标记
            inStack[temp] = 0;              // 将栈内标记置为0
            if(temp == x)                   // 一直弹到x出现为止
                break;
        }
        cnt++;
    }
}

int x[MaxN],y[MaxN];

int main()
{
    while(~scanf("%d%d", &n, &m)) 
    {
        init();     
        for(int i = 1; i <= m; i++)  
        {  
            scanf("%d%d", &x[i], &y[i]);  
            x[i]++; y[i]++;  
            if(x[i] > y[i]) swap(x[i], y[i]);  
        }  
        for(int i = 1; i <= m; i++)  
            for(int j = i + 1; j <= m; j++)  
                if((x[i] <= x[j] && y[i] >= x[j] && y[i] <= y[j]) || (x[i] >= x[j] && x[i] <= y[j] && y[i] >= y[j]))  
                {  
                    Map[i][j+m]=1;
                    Map[i+m][j]=1;
                    Map[j][i+m]=1;  
                    Map[j+m][i]=1;
                }  
                                      // 初始化
        for(int i = 1; i <= m*2; i++) 
            if(dfn[i] == -1)          // 如果某点没被访问过,则对其进行tarjan
                Tarjan(i); 
        int flag = 1;                             
        for(int i = 1; i <= m; i++)  
            if(belong[i] == belong[i + m]) flag = 0; 
        if(flag) cout <<"panda is telling the truth...\n";
        else cout << "the evil panda is lying again\n";
    }
    system("pause"); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值