UVa 11294 - Wedding
题目:有一场婚礼,有n对夫妇參加。他们之间有些人之间有奸情(可能同性),在场的人中有一个公主。
她清楚其它人的人际关系,问是否能安排座位使得两边都是n个人,且公主看不见有奸情的人同一时候在的对面。
分析:2-SAT。直接依照看的流程敲的程序。
1.建图,矛盾的点建立相应的边(与一直关系相反)。
2.利用Tarjan算法计算强连通分量,缩点;
3.推断是否有解(是否有夫妇在同一集合);
4.假设成立,利用拓扑排序求出一组解。输出。
说明:第一个2SAT(⊙_⊙)。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
//link_list_begin
typedef struct enode
{
int point;
enode* next;
}edge;
edge*H1[204],*H2[204];
edge E1[40004],E2[40004];
int e_size1,e_size2;
void link_init( void )
{
e_size1 = 0; e_size2 = 0;
memset( H1, 0, sizeof(H1) );
memset( H2, 0, sizeof(H2) );
memset( E1, 0, sizeof(E1) );
memset( E2, 0, sizeof(E2) );
}
void link_add1( int a, int b )
{
E1[e_size1].point = b;
E1[e_size1].next = H1[a];
H1[a] = &E1[e_size1 ++];
}
void link_add2( int a, int b )
{
E2[e_size2].point = b;
E2[e_size2].next = H2[a];
H2[a] = &E2[e_size2 ++];
}
//link_list_end
int s_id,times,top;
int dfn[204],low[204],use[204],stk[204],oth[204],set[204];
void tarjan( int i, int j )
{
dfn[i] = low[i] = ++ times;
use[i] = 1;
stk[++ top] = i;
for ( edge* p = H1[i] ; p ; p = p->next ) {
if ( !dfn[p->point] ) {
tarjan(p->point, 0);
low[i] = min(low[i], low[p->point]);
}else if ( use[p->point] )
low[i] = min(low[i], dfn[p->point]);
}
if ( dfn[i] == low[i] ) {
s_id ++;
do {
j = stk[top --];
use[j] = 0;
set[j] = s_id;
}while ( j != i );
}
}
void dfs( int i )
{
for ( edge* p = H2[i] ; p ; p = p->next )
if ( !use[p->point] ) {
dfs(p->point);
use[i] = use[p->point];
use[oth[i]] = use[oth[p->point]];
}
use[i] = 1;
use[oth[i]] = 2;
}
void solve( int n )
{
//强连通分量
s_id = times = top = 0;
memset( dfn, 0, sizeof(dfn) );
memset( use, 0, sizeof(use) );
for ( int i = 0 ; i < 2*n ; ++ i )
if ( !dfn[i] )
tarjan(i, 0);
//无解推断
for ( int i = 0 ; i < n ; ++ i )
if ( set[i*2] == set[i*2+1] ) {
printf("bad luck\n");
return;
}else {
oth[set[i*2]] = set[i*2+1];
oth[set[i*2+1]] = set[i*2];
}
//拓扑排序
times = 0;
memset( use, 0, sizeof(use) );
for ( int i = 0 ; i < 2*n ; ++ i )
for ( edge* p = H1[i] ; p ; p = p->next )
if ( set[p->point] != set[i] )
link_add2( set[i], set[p->point] );
for ( int i = 1 ; i <= s_id ; ++ i )
if ( !use[i] )
dfs(i);
for ( int i = 1 ; i < n ; ++ i ) {
if ( i > 1 ) printf(" ");
if ( use[set[i*2]] == use[set[0]] )
printf("%dw",i);
else printf("%dh",i);
}
printf("\n");
}
int main()
{
int n,m,x,y;
char ch1,ch2;
while ( ~scanf("%d%d",&n,&m) && n ) {
link_init();
link_add1( 0, 1 );
for ( int i = 0 ; i < m ; ++ i ) {
scanf("%d%c %d%c",&x,&ch1,&y,&ch2);
x <<= 1; y <<= 1;
if ( ch1 == 'w' ) x ^= 1;
if ( ch2 == 'w' ) y ^= 1;
link_add1( x^1, y );
link_add1( y^1, x );
}
solve( n );
}
return 0;
}
浙公网安备 33010602011771号