• jzoj4350. 【WC2016模拟】废水回收(gates)


    Description

    在这里插入图片描述

    Sample Input

    Input1:
    3 2
    1 0 2 1
    1 0 2 0
    1 1 2 1

    Input2:
    2 1
    1 0 1 0
    1 1 1 1

    Sample Output

    Output1:
    0
    1

    Output2:
    IMPOSSIBLE

    Data Constraint

    在这里插入图片描述

    题解

    此题稍微运用到一点点的2-SAT知识。

    前置芝士:2-SAT
    康这里!

    现在我们知道了2-SAT,那看看这题怎么用。

    分析原题题意:有很多个水阀,然后水阀有两个阀门,只有关掉一个阀门,水阀就会关闭。然后这两个阀门又分别对应着一个开关,开关的方式和上面的一样。

    考虑2-SAT模型!
    先把每个开关拆成两个点,一个表示开启,一个表示关闭。
    然后再看到阀门,我们发现,任意两个阀门必须要有一个开启,所以我们可以连边。
    连完边之后就会出现环的情况,于是我们就可以用tarjan把这个环缩掉。
    当然,这时候还需要判断是不是某个开关的两个点都在同一个环中,如果是就无解。
    缩完点后就变成了一个dag。建立反向边,直接跑一边拓补序即可。
    当然,还要判断开关两个点在不同链的情况,要舍掉其中一个。

    代码

    #include<cstdio>
    #include<cstring>
    #define min(a,b) ((a)<(b)?(a):(b))
    
    using namespace std;
    
    int n,m,q,g;
    int final[2000001],b[1000001],nex[1000001];
    int fir[2000001],c[1000001],las[1000001];
    int dfn[2000001],low[1000001],st[1000001],bz[1000001];
    int l[1000001],r[1000001],a[1000001],f[1000001];
    int ans[1000001],deg[1000001],d[1000001];
    
    void link(int x,int y)
    {
    	b[++q]=y;
    	nex[q]=final[x];
    	final[x]=q;
    }
    
    void dg(int x)
    {
    	dfn[x]=low[x]=++g;
    	st[++st[0]]=x;
    	bz[x]=1;
    	
    	for(int j=final[x];j;j=nex[j])
    		if(!dfn[b[j]])
    		{
    			dg(b[j]);
    			low[x]=min(low[x],low[b[j]]);
    		}
    		else if(bz[b[j]])low[x]=min(low[x],dfn[b[j]]);
    	
    	if(low[x]==dfn[x])
    	{
    		l[x]=q+1;
    		for(;st[st[0]]!=x;st[0]--)
    		{
    			int u=st[st[0]];
    			bz[u]=0,a[++q]=u,f[u]=x;
    		}
    		
    		bz[x]=0,a[++q]=x,f[x]=x;
    		st[0]--;
    		r[x]=q;
    	}
    }
    
    int pd(int x)
    {
    	for(int i=l[x];i<=r[x];i++)
    		if(ans[(a[i]-1)%m+1]>=0)return 1;
    	return 0;
    }
    
    void get(int x)
    {
    	for(int i=l[x];i<=r[x];i++)
    		ans[(a[i]-1)%m+1]=(a[i]-1)/m;
    }
    
    void solve()
    {
    	int t=1,w=0;
    	for(int i=1;i<=2*m;i++)
    		if((f[i]==i)&&(!deg[i]))d[++w]=i;
    	
    	for(;t<=w;t++)
    	{
    		int x=d[t];
    		
    		if(pd(x))continue;
    		get(x);
    		
    		for(int j=fir[x];j;j=las[j])
    		{
    			deg[c[j]]--;
    			if(!deg[c[j]])d[++w]=c[j];
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	
    	memset(final,0,sizeof(final));
    	for(int i=1;i<=n;i++)
    	{
    		int u,v,x,y;
    		scanf("%d%d%d%d",&u,&x,&v,&y);
    		
    		link(u+(x^1)*m,v+y*m);
    		link(v+(y^1)*m,u+x*m);
    	}
    	
    	memset(dfn,0,sizeof(dfn));
    	memset(bz,0,sizeof(bz));
    	st[0]=0;g=0;
    	q=0;
    	
    	for(int i=1;i<=2*m;i++)
    		if(!dfn[i])dg(i);
    	
    	for(int i=1;i<=m;i++)
    		if(f[i]==f[i+m])
    		{
    			printf("IMPOSSIBLE
    ");
    			return 0;
    		}
    	
    	memset(fir,0,sizeof(fir));
    	memset(deg,0,sizeof(deg));
    	q=0;
    	for(int i=1;i<=2*m;i++)
    		for(int j=final[i];j;j=nex[j])
    			if(f[i]!=f[b[j]])
    			{
    				c[++q]=f[i];
    				las[q]=fir[f[b[j]]];
    				fir[f[b[j]]]=q;
    				
    				deg[f[i]]++;
    			}
    	
    	memset(ans,128,sizeof(ans));
    	solve();
    	
    	for(int i=1;i<=m;i++)
    		printf("%d
    ",ans[i]);
    }
    
  • 相关阅读:
    c++中,map的使用
    关于C++中vector<vector<int> >的使用
    python中如何向shell脚本传递带空格的参数
    数组初始化及赋值的方法,memset的使用
    leetcode:首个缺少的最小正整数(js实现。)
    安装cmake过程出错:Error when bootstrapping CMake: Cannot find a C++ compiler that supports both C++11 and the specified C++ flags.
    React系列--三大属性 props refs state
    React系列--组件Component
    React系列--jsx语法及虚拟dom,渲染
    c++的复制构造函数,(郑莉 c++语言程序设计)
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/13492978.html
Copyright © 2020-2023  润新知