poj3207 2-sat基础题

  这个题的意思是有一个0-n-1的顺时针圈, 现在想要给这些圈中的两对数字连线,这些连线可以从圈外连也可以从圈内连, 问能不能再连线不相交的情况下连完所有的数对。考虑到每一个数对的连接只有两种可能, 我们将一个数对看成一个集合, 这个集合有两个元素, 一个是从圆内连线, 一个是从圆外连线, 问题就抽象成了普通的2-sat问题,然后就可以构图, 构图完成后求一下将环缩成一个点, 然后判断集合内两个元素有没有同时在一个环内即可, 若是在则无解, 不在则有解。 这个题还需要注意的是判断两对连线相交的方法。 代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>

using namespace std;
const int maxn = 1000+10;
int n, m;
struct P
{
    int a, b;
}p[500+10];

struct Scc
{
    int V;
    vector<int> G[maxn];   //原始图
    vector<int> rG[maxn];  //反向边
    vector<int> vs;        //后序遍历顶点列表
    bool used[maxn];       //访问标记
    int cmp[maxn];         //所属强连通分量
    void init()
    {
        for(int i=0; i<=V; i++) G[i].clear(), rG[i].clear();
    }
    void add_edge(int from, int to)
    {
        G[from].push_back(to);
        rG[to].push_back(from);
    }
    void dfs(int v)
    {
        used[v] = true;
        for(int i=0; i<G[v].size(); i++)
            if(!used[G[v][i]]) dfs(G[v][i]);
        vs.push_back(v);
    }
    void rdfs(int v, int k)
    {
        used[v] = true;
        cmp[v] = k;
        for(int i=0; i<rG[v].size(); i++)
            if(!used[rG[v][i]]) rdfs(rG[v][i], k);
    }
    int scc()
    {
        memset(used, 0, sizeof(used));
        vs.clear();
        for(int v=1; v<=V; v++)
            if(!used[v]) dfs(v);
        memset(used, 0, sizeof(used));
        int k = 1;
        for(int i=vs.size()-1; i>=0; i--)
            if(!used[vs[i]]) rdfs(vs[i], k++);
        return k-1;
    }
}ss;

int main()
{
    scanf("%d%d", &n, &m);
    for(int i=1; i<=m; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if(a>b) swap(a, b);
        p[i] = (P){a, b};
    }
    ss.V = 2*m;
    ss.init();
    for(int i=1; i<=m; i++)
        for(int j=i+1; j<=m; j++)
        {
            if((p[i].a>p[j].a&&p[i].a<p[j].b&&p[i].b>p[j].b)||
               (p[i].b>p[j].a&&p[i].b<p[j].b&&p[i].a<p[j].a))
            {
                ss.add_edge(2*i-1, 2*j);
                ss.add_edge(2*j, 2*i-1);
                ss.add_edge(2*i, 2*j-1);
                ss.add_edge(2*j-1, 2*i);
            }
        }
    ss.scc();
    bool res = true;
    for(int i=1; i<=m; i++)
        if(ss.cmp[2*i-1]==ss.cmp[2*i])
        {
            res = false;
            break;
        }
    if(res)
        printf("panda is telling the truth...\n");
    else
        printf("the evil panda is lying again");
    return 0;
}

 

posted @ 2016-03-01 16:23  xing-xing  阅读(299)  评论(0编辑  收藏  举报