题解:
裸的2−sat2−sat。
把每个队分成两组,第ii个队的两个小分队编号为和i∗2i∗2;然后根据2−sat2−sat建边,判断强联通即可即判断2∗i−12∗i−1和i∗2i∗2是否在同一个强联通分量。
Code:Code:
#include<bits/stdc++.h>
#define N 10005
using namespace std;
int tot,sum,deep,dfn[N],cnt[N],a[N],low[N],head[N],top,flag[N],color[N];
struct node
{
int vet,next;
}edge[N];
void add(int u,int v)
{
edge[++tot].vet=v;
edge[tot].next=head[u];
head[u]=tot;
}
void tarjan(int u)
{
dfn[u]=low[u]=++deep;
a[++top]=u;flag[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].vet;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}else
if(flag[v])
low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
color[u]=++sum;
flag[u]=false;
while(a[top]!=u)
{
flag[a[top]]=false;
color[a[top--]]=sum;
}
top--;
}
}
int main()
{
int T,m;
while(~scanf("%d%d",&T,&m))
{
for(int i=1;i<=T;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
cnt[a]=2*i-1;
cnt[b]=cnt[c]=2*i;
}
tot=0;
memset(head,-1,sizeof(head));
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
if(cnt[a]!=cnt[b])
if(cnt[a]%2==1&&cnt[b]%2==1)
{
add(cnt[a],cnt[b]+1);
add(cnt[b],cnt[a]+1);
}else
if(cnt[a]%2==0&&cnt[b]%2==0)
{
add(cnt[a],cnt[b]-1);
add(cnt[b],cnt[a]-1);
}else
if(cnt[a]%2==0&&cnt[b]%2==1)
{
add(cnt[a],cnt[b]+1);
add(cnt[b],cnt[a]-1);
}else
if(cnt[a]&1&&cnt[b]%2==0)
{
add(cnt[a],cnt[b]-1);
add(cnt[b],cnt[a]+1);
}
}
memset(dfn,0,sizeof(dfn));
memset(flag,false,sizeof(flag));
sum=deep=top=0;
for(int i=1;i<=2*T;i++)
if(!dfn[i])tarjan(i);
int ans=0;
for(int i=1;i<=T;i++)
if(color[i*2-1]==color[i*2])
{
ans++;
break;
}
if(ans)puts("no");else
puts("yes");
}
return 0;
}