1. 程式人生 > >poj-3648(2-sat)

poj-3648(2-sat)

sync tin nbsp ons bad targe define 可能 oid

題目鏈接:http://poj.org/problem?id=3648

題意:有n對夫妻坐成兩排,其中第0對為新娘新郎。有m對奸情,新娘不願意看到對面排存在奸情,問是否有合理方案,有輸出一組解,否則輸出"bad luck";

思路:

每對夫妻要麽和新郎一排,要麽和新娘一排所以容易想到用2-sat.

我們將丈夫編號為0~n-1,其對應的妻子編號+n(下面用i表示丈夫,i‘表示妻子).

每對奸情則即是矛盾,則與其不矛盾的點連邊,比如a與b矛盾,則連a->b‘,b->a‘,其意思是選a必須連b‘,不能選b。

這裏用一個數組(kx[])表示該點是否可選,或沒被選。 初始值為0,表示未被選,1表示可選及已選,-1表示不可選。

每次選擇了一個點後,就暴力搜接下來必須選擇的點,然後把他們都選擇,其伴侶都標記為不選擇。如果不合法就換一種方式搜。

連邊時要加一條新娘到新郎的邊,因為新郎也可能有奸情,使其矛盾。

過程例如以下:a與新郎有奸情,矛盾,在開始建圖時會使a->新娘,當如果爆搜選了a,則下面選新娘,標記新郎不可選,再通過建的這條邊,發現爆搜a不可行,這樣就避免了新郎與奸情坐一側,這點很重要,而且我想了很久很久。。。。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include
<queue> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=1e5+10; struct node{ int u,v,next; }e[maxn]; int head[maxn],kx[maxn],n,m,top,cnt,st[maxn]; //kx數組判斷是否可選,初始值為0, 1為可選且已選,-1為不可選。 int cp(int x){ return x<=n?x+n:x-n; }//返回cp編號 void add(int u,int v){e[cnt].u=u,e[cnt].v=v,e[cnt].next=head[u],head[u]=cnt++;}
bool dfs(int x)//爆搜,判斷編號x是否可選 { if(kx[x]==1) return true;//可選,且已被選。 if(kx[x]==-1) return false;//不可選 kx[x]=1,kx[cp(x)]=-1,st[++top]=x;//沒被選,但是可被選,所以選入,其cp標為不可選。 for(int i=head[x];i!=-1;i=e[i].next) { if(!dfs(e[i].v))//判斷相連的點是否可選,要選一起選。 return false; } return true; } void solve() { for(int i=1;i<=n;i++) { if(kx[i])//由0~i-1 連邊判斷已被選,不用進行下面操作 continue; top=0; if(!dfs(i))//kx[i]==0,沒被選 ,且不可選 { while(top)//返回由i推到已選點,重新變成沒選狀態。 { kx[st[top]]=kx[cp(st[top])]=0; top--; } if(!dfs(i+n))//i不可選,且i+n也不可選,說明尋找不到答案。 { cout<<"bad luck"<<endl; return ; } } } for(int i=1;i<n;i++)//可以找到解 { if(kx[i]==-1)//當i不可選,則表示新娘不可見,放到新娘一邊 cout<<i<<"h "; else//否則i+n不可選,所以i的妻子放在新娘一邊 cout<<i<<"w "; } cout<<endl; } int main() { std::ios::sync_with_stdio(false); int x,y; char x1,y1; while(cin>>n>>m) { if(!n&&!m) break; memset(kx,0,sizeof(kx)); memset(head,-1,sizeof(head)); cnt=0; for(int i=0;i<m;i++) { cin>>x>>x1>>y>>y1; if(!x) x=n; if(!y) y=n; if(x1==h&&y1==h) add(x,y+n),add(y,x+n); else if(x1==h&&y1==w) add(x,y),add(y+n,x+n); else if(x1==w&&y1==h) add(x+n,y+n),add(y,x); else if(x1==w&&y1==w) add(x+n,y),add(y+n,x); } add(2*n,n);//加一條新娘到新郎的邊,因為新郎可能有奸情 solve(); } return 0; }

poj-3648(2-sat)