您的位置:首页 > 其它

POJ_3648 Wedding 2-Sat

2012-05-05 13:15 417 查看
http://poj.org/problem?id=3648

题意:有N-1对夫妻去参加0号夫妻的婚礼,0号新娘和0号新郎分做桌子的两边,现在已知同一对夫妻不能做在同 一边,而且给出M对“通奸”关系,要求这M对人不能有任意一对人同时做在新郎这一边,问是否有解, 有解则输出解。

思路:2-Sat问题。建图的方法是:0号夫妻中,新郎必须在选,也就是说不能选新娘,我们就可以在新娘和新郎之间加一条边,说明要是选了新娘就必要选新郎,这样就会导致矛盾,同时也就间接地规定不能选新娘了。对于其他的通奸关系(i,j),我们可以建图:(i , j') 和 ( j , i' )。 最后用2-Sat求解即可。

代码:

#include<stdio.h>
#include<string.h>
const int MAXN = 70*2 ;
int N ,M ;
int Gv[MAXN*MAXN] , Gnext[MAXN*MAXN] , Gr[MAXN] , Gc ;
int dfn[MAXN] , low[MAXN] , stack[MAXN] , belong[MAXN] , cf[MAXN];
bool in[MAXN] ;
int top , idx , Bcnt ;
int gv[MAXN*MAXN] ,gnext[MAXN*MAXN] , gr[MAXN] , gc ;
int degree[MAXN] ,que[MAXN] ,front ,rear , col[MAXN];

void init(){
memset(Gr, -1, sizeof(Gr)); Gc = 0 ;
}
void add(int a, int b){
Gv[Gc] = b ;
Gnext[Gc] = Gr[a] ;
Gr[a] = Gc ++ ;
}
void tarjin(int u){
int v ;
low[u] = dfn[u] = ++idx ;
stack[++top] = u ; in[u] = 1 ;
for(int i=Gr[u] ;i!=-1;i=Gnext[i]){
v = Gv[i] ;
if( !dfn[v] ){
tarjin(v);
if(low[v] < low[u]) low[u] = low[v] ;
}
else if( in[v] && dfn[v] < low[u])
low[u] = dfn[v] ;
}
if( dfn[u] == low[u] ){
Bcnt ++ ;
do{
v = stack[top--] ; in[v] = 0 ;
belong[v] = Bcnt ;
}while(u != v) ;
}
}
void add2(int a, int b){
gv[gc] = b ;
gnext[gc] = gr[a] ;
gr[a] = gc++ ;
}
void solve(){
memset(gr , -1,  sizeof(gr)); gc = 0 ;
memset(degree , 0 ,sizeof( degree) ) ;
for(int i=1;i<=2*N;i++){
for(int j=Gr[i] ;j!=-1;j=Gnext[j]){
int v = Gv[j] ;
int fa = belong[i] ;
int fb = belong[v] ;
if( fa != fb){
add2(fb ,fa);
degree[fa] ++ ;
}
}
}
front = rear = 0 ;
for(int i=1;i<=Bcnt;i++){
if( degree[i] == 0)  que[rear++] = i ;
}
memset(col , 0 ,sizeof(col));
while(front != rear){
int v = que[front++] ;
if( col[v] == 0 ){
col[v] = 1 ;
col[ cf[v] ] = -1 ;
}
for(int i=gr[v];i!=-1;i=gnext[i]){
int u = gv[i] ;
if( --degree[u] == 0)   que[rear++]  = u ;
}
}
bool first = 1 ;
for(int i=1;i<=N;i++){
if(first == 0)  printf(" ");
first = 0 ;
if( col[ belong[2*i-1] ] == -1 ){
printf("%dw",i);
}
else
printf("%dh",i);
}
printf("\n");
}
int main(){
int a, b ,c , d ;
char ch1, ch2 ;
while(scanf("%d%d",&N,&M) == 2){
if(0==N && M==0)    break ;
init() ;
for(int i=1;i<=M;i++){
scanf("%d%c %d%c",&a,&ch1,&b,&ch2);
if(a == b)  continue ;
if( ch1=='h' ){
c = 2 * a -1 ; a = 2 * a ;
}
else{
c = 2 * a ; a = 2 * a - 1 ;
}
if( ch2=='h' ){
d = 2 * b - 1 ; b = 2 * b ;
}
else{
d = 2 * b;  b = 2 * b - 1 ;
}
if(a==0){
if(ch1=='h'){
add(b,d);
}
else    continue ;
}
else if(b == 0){
if(ch2=='h'){
add(a,c);
}
else
continue ;
}
else{
add(a,d);
add(b,c);
}
}
N-- ;
top = idx = Bcnt = 0 ;
memset(dfn , 0 ,sizeof(dfn));
memset(in , 0 ,sizeof(in));
for(int i=1;i<=2*N;i++){
if( !dfn[i] )   tarjin(i);
}
bool ok = 1 ;
for(int i=1;i<=N;i++){
if( belong[2*i-1] == belong[2*i] ){
ok = 0 ; break ;
}
cf[ belong[2*i-1] ] = belong[2*i] ;
cf[ belong[2*i] ] = belong[2*i-1] ;
}
if(!ok){
printf("bad luck\n");   continue ;
}
solve() ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: