Party
Problem Description
有 n n n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有 1 1 1人可以列席。在 2 n 2n 2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的 2 2 2个人是不会同时出现在聚会上的。有没有可能会有 n n n 个人同时列席?
Input
n
n
n: 表示有
n
n
n对夫妻被邀请
(
n
<
=
1000
)
(n<= 1000)
(n<=1000)
m
m
m: 表示有
m
m
m 对矛盾关系
(
m
<
(
n
−
1
)
∗
(
n
−
1
)
)
( m < (n - 1) * (n -1))
(m<(n−1)∗(n−1))
在接下来的
m
m
m行中,每行会有
4
4
4个数字,分别是
A
1
,
A
2
,
C
1
,
C
2
A_1,A_2,C_1,C_2
A1,A2,C1,C2
A
1
,
A
2
A_1,A_2
A1,A2分别表示是夫妻的编号
C
1
,
C
2
C_1,C_2
C1,C2 表示是妻子还是丈夫 ,
0
0
0表示妻子 ,
1
1
1是丈夫
夫妻编号从
0
0
0 到
n
−
1
n -1
n−1
Output
如果存在一种情况 则输出YES
否则输出 NO
Sample Input
2
1
0 1 1 1
Sample Output
YES
思路
每对夫妻有两种情况:丈夫到场、妻子到场,记为
u
,
u
′
u,u'
u,u′(或
u
′
,
u
u',u
u′,u)。
若
u
u
u,
v
v
v有矛盾,则添加
u
−
>
v
′
u->v'
u−>v′,
v
−
>
u
′
v->u'
v−>u′两条有向边。
注意
多组输入。
#include<cstdio>
#include<cstring>
#define h(x) (x<=n?x+n:x-n)
using namespace std;
const int maxn=2021,Emaxn=4e6+10;
int head[maxn],ver[Emaxn],Next[Emaxn],tot;
int rhead[maxn],rver[Emaxn],rNext[Emaxn],rtot;
int n,m,a,b,c,d,q[maxn],vis[maxn],qtot,f[maxn],flag;
void add(int u,int v){ver[++tot]=v,Next[tot]=head[u],head[u]=tot;}
void radd(int u,int v){rver[++rtot]=v,rNext[rtot]=rhead[u],rhead[u]=rtot;}
void rdfs(int x){
vis[x]=1;
for(int i=rhead[x];i;i=rNext[i])
if(!vis[rver[i]]) rdfs(rver[i]);
q[qtot++]=x;
}
void dfs(int x,int y){
vis[x]=0; f[x]=y;
for(int i=head[x];i;i=Next[i])
if(vis[ver[i]]) dfs(ver[i],y);
}
int main(){
while(~scanf("%d%d",&n,&m)){
tot=rtot=qtot=flag=0;
memset(head,0,sizeof(head));
memset(rhead,0,sizeof(rhead));
while(m--){
scanf("%d%d%d%d",&a,&b,&c,&d);
a=(c==0?h(a+1):a+1);
b=(d==0?h(b+1):b+1);
add(a,h(b)),add(b,h(a));
radd(h(b),a),radd(h(a),b);
}
for(int i=1;i<=2*n;i++) if(!vis[i]) rdfs(i);
for(int i=qtot-1;i>=0;i--)
if(vis[q[i]]) dfs(q[i],q[i]);
for(int i=1;i<=2*n;i++) if(f[i]==f[h(i)]) flag=1;
puts(flag?"NO":"YES");
}
}
Let’s go home
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
思路
将队长留校看作 u u u,两个队员留校看作 u ′ u' u′(队员是一个整体)。可以用map映射来将成员的标号从 [ 0 , 3 n ) [0,3n) [0,3n)转换到 [ 0 , 2 n ) [0,2n) [0,2n)这 2 n 2n 2n个结点。
#include<cstdio>
#include<cstring>
#include<map>
#define h(x) ((x&1)?x-1:x+1)
using namespace std;
const int maxn=3010,Emaxn=9e6+10;
int n,m,a,b,c,vis[maxn],q[maxn],qtot,f[maxn],flag;
int head[maxn],ver[Emaxn],Next[Emaxn],tot;
int rhead[maxn],rver[Emaxn],rNext[Emaxn],rtot;
void add(int u,int v){ver[++tot]=v,Next[tot]=head[u],head[u]=tot;}
void radd(int u,int v){rver[++rtot]=v,rNext[rtot]=rhead[u],rhead[u]=rtot;}
void rdfs(int x){
vis[x]=1;
for(int i=rhead[x];i;i=rNext[i])
if(!vis[rver[i]]) rdfs(rver[i]);
q[qtot++]=x;
}
void dfs(int x,int y){
vis[x]=0; f[x]=y;
for(int i=head[x];i;i=Next[i])
if(vis[ver[i]]) dfs(ver[i],y);
}
int main(){
while(~scanf("%d%d",&n,&m)){
map<int,int> mp;
for(int i=0;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
mp[a]=tot++,mp[b]=tot,mp[c]=tot++;
}
while(m--){
scanf("%d%d",&a,&b);
a=mp[a],b=mp[b];
int x=a,y=b;
if(x&1) x=h(x);
if(y&1) y=h(y);
if(x==y&&a!=x&&b!=y)
add(h(x),x),radd(x,h(x));
else if(x!=y){
if(a!=x) a=h(x);
if(b!=y) b=h(y);
add(a,h(b)),add(b,h(a)),radd(h(b),a),radd(h(a),b);
}
}
for(int i=0;i<2*n;i++) if(!vis[i]) rdfs(i);
for(int i=2*n-1;i>=0;i--) if(vis[q[i]]) dfs(q[i],q[i]);
for(int i=0;i<2*n;i++) if(f[i]==f[h(i)]) flag=1;
puts(flag?"no":"yes");
tot=rtot=qtot=flag=0;
memset(head,0,sizeof(head));
memset(rhead,0,sizeof(rhead));
}
}