POJ 3648 2SAT求解方案

题意:有个新娘和新郎,然后请了n-1对夫妇,其中有m对有不正当关系……而新娘不想看到有不正当关系的在一起,新娘可以看到在她对面的人,而在她同一边的看不到,所以即使有不正当关系的在新娘同一边也是可以的。问:有没有可能的方案符合题意?

这题看了一天了……还是没弄明白其建图是什么回事……唉……看了魏神的博客,然后还是研究了好久,不知道为什么那样建图,晕……等过段时间再回来看再理解吧!

就把这个作为2SAT求解方案的模板咯,嘿嘿……

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define sc(a,b) scanf("%d%d",&a,&b)
#define pri(a) printf("%d\n",a)
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define MM 1000005
#define MN 100050
#define INF 1000000009
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
int DFN[MN],LOW[MN],vis[MN],belong[MN];
int n,m,index,Count,conflict[MN],color[MN],id[MN];
stack<int>Stack,q;
vector<int>e[MN],ee[MN]; //e为原图,ee为新图
void init()
{
    index=Count=0;
    mem(vis,0); mem(DFN,0); mem(LOW,0); mem(belong,0);
    mem(conflict,0); mem(color,0); mem(id,0);
    for(int i=0;i<=2*n;i++) e[i].clear(),ee[i].clear();
    while(!Stack.empty()) Stack.pop();
}
void tarjan(int u)
{
    DFN[u]=LOW[u]=++index;
    vis[u]=1;
    Stack.push(u);
    int v,i,l=e[u].size();
    for(i=0;i<l;i++)
    {
        v=e[u][i];
        if(!DFN[v])
        {
            tarjan(v);
            LOW[u]=min(LOW[u],LOW[v]);
        }
        else if(vis[v]&&DFN[v]<LOW[u]) LOW[u]=DFN[v];
    }
    if(DFN[u]==LOW[u])
    {
        Count++;
        do
        {
            v=Stack.top();
            Stack.pop();
            vis[v]=0;
            belong[v]=Count;
        }while(v!=u);
    }
}
void topsort()  //对新图拓扑排序并颜色标记
{
    int i,u,len;
    for(i=1;i<=Count;i++)
        if(!id[i]) q.push(i);
    while(!q.empty())
    {
        u=q.top(); q.pop(); len=ee[u].size();
        if(!color[u]) color[u]=1,color[conflict[u]]=2;
        for(i=0;i<len;i++)
            if(--id[ee[u][i]]==0) q.push(ee[u][i]);
    }
}
void buildMap()  //建立新图
{
    int u,v,i,len;
    for(u=0;u<2*n;u++)
    {
        len=e[u].size();
        for(i=0;i<len;i++)
        {
            v=e[u][i];
            if(belong[u]!=belong[v])
                ee[belong[v]].push_back(belong[u]),id[belong[u]]++;
        }
    }
}
void twoSAT()
{
    int i;
    for(i=0;i<2*n;i++)
        if(!DFN[i]) tarjan(i);
    for(i=0;i<n;i++)
        if(belong[2*i]==belong[2*i+1])
        {
            puts("bad luck");
            return ;
        }
        else conflict[belong[2*i]]=belong[2*i+1],
        conflict[belong[2*i+1]]=belong[2*i]; //不同的强连通就是冲突
    buildMap();
    topsort();
    for(i=2;i<2*n;i+=2)
        if(color[belong[i]]==color[belong[0]]) printf("%dw ",i/2);
        else printf("%dh ",i/2);
    puts("");
}
int main()
{
    int a0,b0,b1,a1,x,y,i,j;
    char c1,c2;
    while(sc(n,m)&&(n||m))
    {
        init();
        while(m--)
        {
            scanf("%d%c %d%c",&x,&c1,&y,&c2);
            if(c1 == 'h') a0 = 2 * x, a1 = 2 * x + 1;
            else a0 = 2 * x + 1, a1 = 2 * x; //为什么要这样建图还是弄不明白……
            if(c2 == 'h') b0 = 2 * y, b1 = 2 * y + 1;
            else b0 = 2 * y + 1, b1 = 2 * y;
            e[a1].push_back(b0);
            e[b1].push_back(a0);
        }
        e[0].push_back(1);
        twoSAT();
    }
    return 0;
}


你可能感兴趣的:(POJ 3648 2SAT求解方案)