您的位置:首页 > 其它

hdu 4115(2-SAT) 2011 成都现场赛E题

2014-03-22 22:04 459 查看
题意:两个人玩剪刀石头布,你知道对手出拳的序列(就是每一步出哪个)给你两种限制,i与j相同和不相同。你赢的条件是你不能输给对方一次,问你能不能赢。

思路:典型的2-SAT题目,对于每次猜拳,排除你会输的那一次然后就只剩两个选择了,接下来就是分类讨论。

我们定义第一个能出的为真,另一个为假

首先分成 i次 与j次不能出的相同,那么

  a b 1 表示 a^b = 1

  a b 0 表示 a^b = 0

然后是不同的,那么

  对于a b 1情况

    a b 出那个已经知道了

  a b 0情况

    !a->b ^ !b->a 都能出的为假

    a->!b ^ b->!a 都能出的为真

代码如下:

/**************************************************
* Author     : xiaohao Z
* Blog     : http://www.cnblogs.com/shu-xiaohao/ * Last modified : 2014-03-22 16:59
* Filename     : hdu_chengdu2.cpp
* Description     :
* ************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define MP(a, b) make_pair(a, b)
#define PB(a) push_back(a)

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<unsigned int,unsigned int> puu;
typedef pair<int, double> pid;
typedef pair<ll, int> pli;
typedef pair<int, ll> pil;

const int INF = 0x3f3f3f3f;
const double eps = 1E-6;
const int LEN = 100000+10;
int n, m, chu[LEN][4], vis[LEN], sccn[LEN];
vector<int> Map[LEN], rMap[LEN], vs;

void dfs(int v){
vis[v] = 1;
for(int i=0; i<Map[v].size(); i++) if(!vis[Map[v][i]]) dfs(Map[v][i]);
vs.PB(v);
}

void rdfs(int v, int k){
vis[v] = 1;
sccn[v] = k;
for(int i=0; i<rMap[v].size(); i++) if(!vis[rMap[v][i]]) rdfs(rMap[v][i], k);
}

int scc(){
memset(vis, 0, sizeof vis);
vs.clear();
for(int v=0; v<2*n; v++) if(!vis[v]) dfs(v);
memset(vis, 0, sizeof vis);
int k = 0;
for(int i=vs.size()-1; i>=0; i--) if(!vis[vs[i]]) rdfs(vs[i], k++);
return k;
}

bool twosat(){
scc();
//    for(int i=0; i<2*n; i++)cout << sccn[i] << ' ';
//    cout << endl;
for(int i=0; i<2*n; i+=2){
if(sccn[i] == sccn[i^1]){
//cout << i << endl;
return false;
}
}
return true;
}

void add(int a, int b){
Map[a].PB(b);
rMap[b].PB(a);
}

void addNot(int a, int b){
a*=2; b*=2;
add(a, b^1);
add(b^1, a);
add(b, a^1);
add(a^1, b);
}

void addYes(int a, int b){
a*=2; b*=2;
add(a, b);
add(b, a);
add(a^1, b^1);
add(b^1, a^1);
}

void addSame(int a){
add(a^1, a);
}

void addNotSame(int a, int b){
add(a, b^1);
add(b, a^1);
}

int main()
{
//    freopen("in.txt", "r", stdin);

int T, a, b, c;
scanf("%d", &T);
for(int kase=1; kase<=T; kase++){
for(int i=0; i<LEN; i++) Map[i].clear();
for(int i=0; i<LEN; i++) rMap[i].clear();
memset(chu, 0, sizeof chu);
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++){
int tmp;
scanf("%d", &tmp);
chu[i][0] = tmp;
chu[i][(tmp)%3+1] = 1;
}
for(int i=0; i<m; i++){
scanf("%d%d%d", &a, &b, &c);
a--; b--;
if(chu[a][0] == chu[b][0]){
if(c == 1) addNot(a, b);
else addYes(a, b);
}else{
int fa = -1, fb = -1;
for(int j=1; j<4; j++){
if(!chu[a][j]) fa++;
if(!chu[b][j]) fb++;
if(chu[a][j] == chu[b][j] && chu[b][j] == 0) break;
}
if(c == 0){
addSame((2*a)^fa);
addSame((2*b)^fb);
}else{
addNotSame((2*a)^fa, (2*b)^fb);
}
}
}
printf("Case #%d: ", kase);
if(twosat())printf("yes\n");
else printf("no\n");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: