Eliminate the Conflict

一、题目

点此看题

二、解法

因为不能失败,所以只能有两种选择,我们尝试把它转化成 2 − sat 2-\text{sat} 2sat问题。

先处理出能选的两种出法( a i , b i a_i,b_i ai,bi),考虑 k = 0 k=0 k=0(相同)时候怎么建图:

  • 如果 a i ≠ a j a_i\not=a_j ai=aj,连 ( a i , b j ) , ( a j , b i ) (a_i,b_j),(a_j,b_i) (ai,bj),(aj,bi)
  • 如果 a i ≠ b j a_i\not=b_j ai=bj,连 ( a i , a j ) , ( b j , b j ) (a_i,a_j),(b_j,b_j) (ai,aj),(bj,bj)
  • 如果 b i ≠ a j b_i\not=a_j bi=aj,连 ( b i , b j ) , ( a j , a i ) (b_i,b_j),(a_j,a_i) (bi,bj),(aj,ai)
  • 如果 b i ≠ b j b_i\not=b_j bi=bj,连 ( b i , a j ) , ( b j , a i ) (b_i,a_j),(b_j,a_i) (bi,aj),(bj,ai)

k = 1 k=1 k=1的时候改一下判断条件就行了,康康代码。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
#include <cmath>
using namespace std;
const int M = 20005;
int read()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
    return num*flag;
}
int T,n,m,tot,Index,cnt,a[M],b[M];
int f[M],dfn[M],low[M],in[M],col[M];
stack<int> st;
struct edge
{
    int v,next;
}e[10*M];
void add(int u,int v)
{
    e[++tot]=edge{v,f[u]},f[u]=tot;
}
void tarjan(int u)
{
    in[u]=1;st.push(u);
    dfn[u]=low[u]=++Index;
    for(int i=f[u];i;i=e[i].next)
    {
        int v=e[i].v;
        if(!dfn[v])
            tarjan(v),low[u]=min(low[u],low[v]);
        else if(in[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        int v=0;cnt++;
        do
        {
            v=st.top();st.pop();
            in[v]=0;col[v]=cnt;
        }while(v!=u);
    }
}
int check(int a,int b,int k)
{
	if(k==0) return a!=b;
	return a==b;
}
signed main()
{
	T=read();
	for(int cs=1;cs<=T;cs++)
	{
		n=read();m=read();
	    tot=Index=cnt=0;
	    memset(f,0,sizeof f);
	    memset(dfn,0,sizeof dfn);
	    memset(low,0,sizeof low);
	    memset(col,0,sizeof col);
		for(int i=1;i<=n;i++)
		{
			int x=read();
			if(x==1) a[i]=2,b[i]=3;
			if(x==2) a[i]=1,b[i]=3;
			if(x==3) a[i]=1,b[i]=2;
		}
		for(int i=1;i<=m;i++)
		{
			int x=read(),y=read(),k=read();
			if(check(a[x],a[y],k))
			{
				add(x,y+n);
				add(y,x+n);
			}
			if(check(a[x],b[y],k))
			{
				add(x,y);
				add(y+n,x+n);
			}
			if(check(b[x],a[y],k))
			{
				add(x+n,y+n);
				add(y,x);
			}
			if(check(b[x],b[y],k))
			{
				add(x+n,y);
				add(y+n,x);
			}
		}
		printf("Case #%d: ",cs);
		for(int i=1;i<=n;i++)
			if(!dfn[i]) tarjan(i);
		for(int i=1;i<=n;i++)
			if(col[i]==col[i+n])
			{
				puts("no");
				goto In;
			}
		puts("yes");
		In:;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值