POJ-3648(2-SAT)

28 篇文章 0 订阅
5 篇文章 0 订阅

题目:http://poj.org/problem?id=3648

第四道2-SAT,本来以为很简单的,没想到WA了一个晚上~~~~(>_<)~~~~ 。刚开始没考虑到bride和groom的通奸情况,然后想到到了又考虑错了以为bride不能看到那个情夫,看了discuss才知道原来bride看到情夫也没关系,毕竟bride看不到自己,真是给跪了。。。


#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define MAX_N 1005

int N, M;
bool predefined[MAX_N * 2];	//those who must sit at bride's side
vector<int> out[MAX_N * 4];
bool mark[MAX_N * 4];		//mark[2i] = 1, i sit at bride side; mark[2i+1] = 1, i sit at groom side
int stack[MAX_N * 4], cnt;

inline void addEdge(int i, int j){//i can not sit in the same side with j
	int x =  i << 1, y = j << 1;
	out[x].push_back(y+1);
	out[y+1].push_back(x);
	out[x+1].push_back(y);
	out[y].push_back(x+1);
}
inline void arrange(int i, int j){
	if(i > j) swap(i, j);
	int x = i << 1, y = j << 1;
	if(i == 0){//j must seat at bride's side so that bride can not see her
		predefined[j] = true;
	}
	else if(i == 1){//it does not matter as the bride can no see herself
		
	}
	else{//i and j can not both sit at groom's side
		out[x+1].push_back(y);
		out[y+1].push_back(x);
	}
}
inline int IDtoInt(const char* s){//husbands' ids are even, wives' ids are odd
	int id = 0;
	for(; isdigit(*s); ++s) id = id * 10 + *s - '0';
	if(*s == 'h') return id << 1;
	return id * 2 + 1;
}
inline char* IntToID(char* s, int n){
	if(n & 1) sprintf(s, "%dw", n >> 1);
	else sprintf(s, "%dh", n >> 1);
	return s;
}

void init()
{
	memset(predefined, 0, N<<1);
	memset(mark, 0, N<<2);
	for(int i = N*4-1; i > -1; --i) out[i].clear();
}
void build()
{
	int i, x;
	char l[8], r[8];
	for(i = 0; i < N; ++i){
		x = i << 1;
		addEdge(x, x + 1);
	}
	for(i = 0; i < M; ++i){//those can not sit at the same table
		scanf("%s%s", l, r);
		arrange(IDtoInt(l), IDtoInt(r));
	}
}
bool dfs(int x)
{
	if(mark[x ^ 1]) return false;
	if(mark[x]) return true;
	mark[x] = true;
	stack[cnt++] = x;
	const vector<int>& v = out[x];
	for(int i = v.size() - 1; i > -1; --i){
		if(!dfs(v[i])) return false;
	}
	return true;
}
bool test()
{
	int i, n = N << 1;
	if(!dfs(0 << 1 | 1)) return false;	//groom must sit at groom's side
	if(!dfs(1 << 1)) return false;		//bride must sit at bride's side
	//those predefined must sit at bride's side
	for(i = 2; i < n; ++i){
		if(predefined[i] && !dfs(i << 1)) return false;
	}
	//normal 2-SAT
	for(i = 2; i < n; ++i){
		cnt = 0;
		if(!dfs(i << 1)){
			while(cnt) mark[stack[--cnt]] = false;
			if(!dfs(i << 1 | 1)) return false;
		}
	}
	return true;
}
void print()
{
	int i, j, n = N << 1, sum = 0;
	char s[8];
	bool first = true;
	for(i = 2; i < n && sum < N; i += 2){
		//check if the husband or the wife should sit at the bride's side
		j = i;
		if(!mark[i << 1]) j = i ^ 1;
		++sum;
		if(first) first = false;
		else putchar(' ');
		printf("%s", IntToID(s, j));
	}
	puts("");
}

int main()
{
	while(scanf("%d%d", &N, &M), N){
		init();
		build();
		if(test()) print();
		else puts("bad luck");
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值