Let’s go home
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2756 Accepted Submission(s): 1192
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
一道比较明显的2-SAT,现在我们主要考虑如何建图。
考虑建图:
对于第一种队伍关系:
- a走,b,c留
- b走,c走,a留
- c走,b走,a留
- a留,b,c走
- b留,c留,a走
- c留,b留,a走
对于第二种关系:
- a走,b留
- b走,a留
然后对于每个队员跑一次tarjan即可,但是这道题并没有说队员是连续的,而是说每个队员有编号,所以我们要用map来离散化每个队员的编号。但是好像这道题数据比较水,不离散化,当成编号连续也能AC
然后检查每个队员,如果这个队员走和这个队员留在同一个强连通分量当中,就输出no,不然输出yes
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=10010,M=100010;
int n,m,dfn[N],col[N],low[N],vis[N],cnt,co,base,flag,idx;
int head[N],nex[M],to[M],tot;
stack<int> st;
unordered_map<int,int> mp;
inline void add(int a,int b){
to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
}
inline void init(){
memset(head,0,sizeof head); memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low); memset(col,0,sizeof col);
cnt=co=tot=flag=idx=0; mp.clear();
}
void tarjan(int x){
dfn[x]=low[x]=++cnt; st.push(x); vis[x]=1;
for(int i=head[x];i;i=nex[i]){
if(!dfn[to[i]]){
tarjan(to[i]); low[x]=min(low[x],low[to[i]]);
}else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
}
if(dfn[x]==low[x]){
co++;
while(1){
int u=st.top(); st.pop(); vis[u]=0;
col[u]=co; if(u==x) return ;
}
}
}
signed main(){
while(~scanf("%d %d",&n,&m)){
init(); base=3*n;
for(int i=1;i<=n;i++){
int a,b,c; scanf("%d %d %d",&a,&b,&c);
mp[a]=++idx; mp[b]=++idx; mp[c]=++idx;
add(mp[a]+base,mp[b]); add(mp[a]+base,mp[c]);
add(mp[b]+base,mp[a]); add(mp[b]+base,mp[c]+base);
add(mp[c]+base,mp[a]); add(mp[c]+base,mp[b]+base);
add(mp[a],mp[b]+base); add(mp[a],mp[c]+base);
add(mp[b],mp[a]+base); add(mp[b],mp[c]);
add(mp[c],mp[a]+base); add(mp[c],mp[b]);
}
while(m--){
int a,b; scanf("%d %d",&a,&b);
add(mp[a],mp[b]+base); add(mp[b],mp[a]+base);
}
for(int i=1;i<=6*n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=base&&!flag;i++) if(col[i]==col[i+base]) flag++;
puts(flag?"no":"yes");
}
return 0;
}