题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1824
Let's go home
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2588 Accepted Submission(s): 1125
Problem Description
小时候,乡愁是一枚小小的邮票,我在这头,母亲在那头。
—— 余光中
集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。
Input
第一行有两个整数,T和M,1<=T<=1000表示队伍数,1<=M<=5000表示对数。
接下来有T行,每行三个整数,表示一个队的队员编号,第一个队员就是该队队长。
然后有M行,每行两个整数,表示一对队员的编号。
每个队员只属于一个队。队员编号从0开始。
Output
可行输出yes,否则输出no,以EOF为结束。
Sample Input
1 2 0 1 2 0 1 1 2 2 4 0 1 2 3 4 5 0 3 0 4 1 3 1 4
Sample Output
yes no
Author
威士忌
Source
HDOJ 2007 Summer Exercise(3)- Hold by Wiskey
Recommend
威士忌 | We have carefully selected several similar problems for you: 1823 1826 1827 1822 1825
题意:
集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。
分析:
其实就是简单的2-SAT问题判断,每个人有两种选择:留=0或走=1.
-
然后该2-SAT要满足两类条件,第一类是 队长留 or 另外两个队员留.
-
第二类是由M指出的 一对队员a和b的冲突条件.
假设a b c 组成一个队,且a是队长,那么由于队长a与队员(b,c)组合二者只能选其一,
TS.add_and_clause(b,0,c,0);//b留c留
TS.add_and_clause(c,0,b,0);//c留b留
TS.add_and_clause(a,1,b,0);//a走b留
TS.add_and_clause(a,1,c,0);//a走c留
TS.add_and_clause(b,1,a,0);//b走a留
TS.add_and_clause(c,1,a,0);//c走a留
对于另外M个条件的a与b来说有:
TS.add_and_clause(a,0,b,1);//a留,导致b走
TS.add_and_clause(b,0,a,1);//b留,导致a走
//注意用的是AND
这样错了好几次
This is the code:
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define pppp cout<<endl;
#define EPS 1e-8
#define LL long long
#define ULL unsigned long long //1844674407370955161
#define INT_INF 0x3f3f3f3f //1061109567
#define LL_INF 0x3f3f3f3f3f3f3f3f //4557430888798830399
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。
const int dr[]= {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[]= {-1, 1, 0, 0, -1, 1, -1, 1};
int read()//输入外挂
{
int ret=0, flag=0;
char ch;
if((ch=getchar())=='-')
flag=1;
else if(ch>='0'&&ch<='9')
ret = ch - '0';
while((ch=getchar())>='0'&&ch<='9')
ret=ret*10+(ch-'0');
return flag ? -ret : ret;
}
const int maxn= 100000+10;
struct TwoSAT
{
int n;//原始图的节点数(未翻倍)
vector<int> G[maxn*2];//G[i]==j表示如果mark[i]=true,那么mark[j]也要=true
bool mark[maxn*2];//标记
int S[maxn*2],c;//S和c用来记录一次dfs遍历的所有节点编号
void init(int n)
{
this->n=n;
for(int i=0; i<2*n; i++)
G[i].clear();
memset(mark,0,sizeof(mark));
}
//加入(x,xval)或(y,yval)条件
//xval=0表示假,yval=1表示真
void add_or_clause(int x,int xval,int y,int yval)//表示或的意思
{
x=x*2+xval;
y=y*2+yval;
G[x^1].push_back(y);
G[y^1].push_back(x);
}
//加入(x,xval)且(y,yval)条件
//xval=0表示假,yval=1表示真
void add_and_clause(int x,int xval,int y,int yval)//表示或的意思
{
x=x*2+xval;
y=y*2+yval;
G[x].push_back(y);
}
//从x执行dfs遍历,途径的所有点都标记
//如果不能标记,那么返回false
bool dfs(int x)
{
if(mark[x^1])
return false;//这两句的位置不能调换
if(mark[x])
return true;
mark[x]=true;
S[c++]=x;
for(int i=0; i<G[x].size(); i++)
if(!dfs(G[x][i]))
return false;
return true;
}
//判断当前2-SAT问题是否有解
bool solve()
{
for(int i=0; i<2*n; i+=2)
if(!mark[i] && !mark[i+1])
{
c=0;
if(!dfs(i))
{
while(c>0)
mark[S[--c]]=false;
if(!dfs(i+1))
return false;
}
}
return true;
}
} TS;
int main()
{
//freopen("D:\\chnegxubianji\\inORout\\in.txt", "r", stdin);
//freopen("D:\\chnegxubianji\\inORout\\out.txt", "w", stdout);
int n,m;
while(~scanf("%d%d",&n,&m))
{
TS.init(n*3);
while(n--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
TS.add_and_clause(b,0,c,0);//b留c留
TS.add_and_clause(c,0,b,0);//c留b留
TS.add_and_clause(a,1,b,0);//a走b留
//TS.add_and_clause(b,0,a,1);//b留a走
TS.add_and_clause(a,1,c,0);//a走c留
//TS.add_and_clause(c,0,a,1);//c留a走
TS.add_and_clause(b,1,a,0);//b走a留
//TS.add_and_clause(a,0,b,1);//a留b走
TS.add_and_clause(c,1,a,0);//c走a留
//TS.add_and_clause(a,0,c,1);//a留c走
//TS.add_and_clause(b,1,c,1);//b走c走
//TS.add_and_clause(c,1,b,1);//c走b走
}
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
TS.add_and_clause(a,0,b,1);//a留,导致b走
TS.add_and_clause(b,0,a,1);//b留,导致a走
}
bool flag=TS.solve();
if(flag)
puts("yes");
else
puts("no");
}
return 0;
}