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;
}

UVa 11294 - Wedding

时间: 2024-08-03 11:28:34

UVa 11294 - Wedding的相关文章

UVA 11294 - Wedding(Two-Set)

UVA 11294 - Wedding 题目链接 题意:有n对夫妻,0号是公主.如今有一些通奸关系(男男,女女也是可能的)然后要求人分配在两側.夫妻不能坐同一側.而且公主对面一側不能有两个同奸的人,问方案 思路:2-set,建图.一共2n个人,设偶数是丈夫,奇数是妻子.左側为false,右側为true,然后丈夫妻子建一条true false 或 false true的边,然后然公主在左側.那么同奸的一对至少一个为false,建一条边,然后2-set判定就可以 代码: #include <cstd

UVA - 11294 Wedding(2-SAT)

题目大意:有N-1对夫妻参加一个婚宴,所有人都坐在一个长长的餐桌左侧或者右侧,新郎和新娘面做面坐在桌子的两侧.由于新娘的头饰很复杂,她无法看到和她坐在同一侧餐桌的人,只能看到对面餐桌的人.任意一对夫妻不能坐在桌子的同侧,另外有m对人吵过架,而新娘不希望看到两个吵过架的人坐在他的对面,问如何安排这些座位 解题思路:设mark[2*i]被标记时表示的是第i对夫妻的妻子跟新娘坐在同一侧,mark[2 * i + 1]被标记时表示的是第i对夫妻的丈夫跟新娘坐同一侧 设吵架的两人是i和j 如果吵过架的人都

uva 11294 2-SAT问题

英文太差了, 这个题目愣是半天没看懂 , 后面看别人翻译才看懂 ,  英语是硬伤啊 题目大意:给 n 对夫妇安排座位 , 0h , 0w表示新郎新娘 , 新娘只能看到坐在她对面那一排的人 , 要求: 1.同一对新郎新娘不能做在同一侧 2.有m对人互为通奸(可以男男.女女.男女) , 新娘不能同时看到互为通奸的两个人. 注意:新郎也有可能和其他人通奸 做法: 1.分两种情况讨论 , 新娘在左侧 , 新娘在右侧 , 分别建图进行 2-SAT算法 2.不分左侧还是右侧 , 只分和新娘同侧或不同侧 下面

UVA 11294 POJ 3648 Wedding

题意: 婚礼上新郎新娘坐在桌子两侧  新娘只能看见对面的人  已知一些人有XX关系-  新娘不想看见有关系的同时坐在对面  问  满足条件的情况下  新娘这边做的人是谁 思路: 新郎那一边的约束最多  有利于解题  那么就变成了  一个人要不要坐新郎这边的2-sat问题  因此可以先求新郎这边的人  然后反一下就是新娘这边的了  注意  新郎是必选点  而且  不能选和新郎有XX关系的- 代码: #include<cstdio> #include<cstring> #include

UVA 11450 Wedding shopping(DP)

One of our best friends is getting married and we all are nervous because he is the first of us who is doing something similar. In fact, we have never assisted to a wedding, so we have no clothes or accessories, and to solve the problem we are going

uva 11294

Problem E: Wedding Up to thirty couples will attend a wedding feast, at which they will be seated on either side of a long table. The bride and groom sit at one end, opposite each other, and the bride wears an elaborate headdress that keeps her from

ACM-ICPC Dhaka Regional 2012 题解

B: Uva: 12582 - Wedding of Sultan 给定一个字符串(仅由大写字母构成)一个字母表示一个地点,经过这个点或离开这个点都输出这个地点的字母) 问: 每个地点经过的次数(维护一个栈就可以了,注意进入起点和离开起点都不算入起点的次数) #include<cstdio> #include<cstring> #include<stack> #include<iostream> #include<algorithm> using

UVA - 1420 Priest John&#39;s Busiest Day

题目大意:有一个司仪,要主持 n 场婚礼,给出婚礼的起始时间和终止时间,每个婚礼需要超过一半的时间做为仪式,并且仪式不能终止.问说司仪能否主持 n 场婚礼. 解题思路:贪心,为了尽量主持多的婚礼,每场的仪式时间就一定要尽量短 d = (t - s) / 2 + 1,(因为必须大于一半,所以加 1).然后按照每场婚礼可以最晚结束的时间排序 t - d,(因为要满足所有的婚礼,所以尽量解决早点的仪式,腾出时间来给后面的婚礼),维护一个占用时间值即可. #include <cstdio> #incl

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d