zoukankan      html  css  js  c++  java
  • 【2019.8.14 慈溪模拟赛 T2】黑心老板(gamble)(2-SAT)

    (2-SAT)

    考虑每个点只能选择(R)(B),可以看作选(0)(1)

    然后对于给出的关系式,若其中一个位置满足关系式,另两个位置就必须不满足关系式,这样就可以对于每个关系式建出(6)条边。

    然后就是裸的(Tarjan)(2-SAT)一组解的板子了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 5000
    #define K 10000
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    using namespace std;
    int n,k,a[K+5][5],p[K+5][5];
    class TwoSatSolver//2-SAT
    {
    	private:
    		#define SZ 2*N
    		#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    		int ee,lnk[SZ+5],d,T,cnt,dfn[SZ+5],low[SZ+5],col[SZ+5],IS[SZ+5],S[SZ+5];
    		char ans[N+5];struct edge {int to,nxt;}e[6*K+5];
    		I void Tarjan(CI x,CI lst=0)//Tarjan缩点
    		{
    			RI i;for(dfn[x]=low[x]=++d,IS[S[++T]=x]=1,i=lnk[x];i;i=e[i].nxt)
    				dfn[e[i].to]?(IS[e[i].to]&&Gmin(low[x],dfn[e[i].to]))
    				:(Tarjan(e[i].to,x),Gmin(low[x],low[e[i].to]));
    			if(dfn[x]^low[x]) return;col[x]=++cnt,IS[x]=0;
    			W(S[T]^x) col[S[T]]=cnt,IS[S[T--]]=0;--T;
    		}
    	public:
    		I void Solve()
    		{
    			RI i;for(i=1;i<=k;++i)//根据给出的关系式建边
    				add(2*a[i][1]-p[i][1],2*a[i][2]-(p[i][2]^1)),
    				add(2*a[i][1]-p[i][1],2*a[i][3]-(p[i][3]^1)),
    				add(2*a[i][2]-p[i][2],2*a[i][1]-(p[i][1]^1)),
    				add(2*a[i][2]-p[i][2],2*a[i][3]-(p[i][3]^1)),
    				add(2*a[i][3]-p[i][3],2*a[i][1]-(p[i][1]^1)),
    				add(2*a[i][3]-p[i][3],2*a[i][2]-(p[i][2]^1));
    			for(i=1;i<=2*n;++i) !dfn[i]&&(Tarjan(i),0);//Tarjan缩点
    			for(i=1;i<=n;++i)
    			{
    				if(col[2*i-1]==col[2*i]) return (void)puts("-1");//若两种情况在同一强连通分量中,无解
    				ans[i]=col[2*i-1]>col[2*i]?'R':'B';//选择所处强连通分量编号较小的,即拓扑序较大的
    			}puts(ans+1);//输出答案
    		}
    }S;
    int main()
    {
    	freopen("gamble.in","r",stdin),freopen("gamble.out","w",stdout);
    	RI i;char c[5];for(scanf("%d%d",&n,&k),i=1;i<=k;++i)
    		scanf("%d%s%d%s%d%s",&a[i][1],&c[1],&a[i][2],&c[2],&a[i][3],&c[3]),//读入
    		p[i][1]=c[1]=='B',p[i][2]=c[2]=='B',p[i][3]=c[3]=='B';//转化
    	return S.Solve(),0;
    }
    
  • 相关阅读:
    Integer值判断是否相等问题
    Java连接Redis
    oracle 10G 没有 PIVOT 函数怎么办,自己写一个不久有了
    前端修炼(第三天)函数
    前端 JS 修炼(第一天)包装对象、作用域、创建对象
    linux oracle 启动全过程
    「android」webview中文乱码
    「dos」bat单条命令跨多行
    「股票」东方财富网公式-缩量
    「android」as javadoc乱码
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Contest20190814T2.html
Copyright © 2011-2022 走看看