zoukankan      html  css  js  c++  java
  • 「LG4782 模板 2-SAT 问题」

    题目

    来学(2)-(sat)

    这个东西确实不难

    这个算法就是给你一堆(bool)变量(x_1,x_2...x_n),之后给你一些限制

    限制的形式就是给你一对((u,o1,v,o2))

    (x_u=o1)或者(x_v=o2)

    之后满足所有限制

    这个东西非常容易就能抽象成一个图论模型

    我们把每个(x_i)拆成(i)(i')两个点,分别表示真和假

    我们对于每一个限制,连出去一些边,边((x,y))的含义是选择了(x)就必须选择(y)

    举个例子吧

    如果一条限制是

    [(u,0,v,1) ]

    那么(u)(v)连边,表示(x_u=1)的时候(x_v)也得等于(1)

    同时(v')(u')连边,表示(x_v=0)的时候(x_u)只能等于(0)

    这样的话如果从(i)能通过这种边一路推到(i')就表示让(x_i=1)的话就必须让(x_i=0)这显然不合理

    于是就能判断无解情况了,一个(tarjan)下去找一个强联通分量

    还有些题目需要我们构造出一组可行解

    其实就是输出(col[i]<col[i'])

    (col[i])就是这个点所属强联通分量的编号

    看起来很神奇,其实是这样的

    我们考虑把(tarjan)缩完点的图建出来,发现我们肯定是尽量优先选择那些拓扑序较大的,因为优先选择拓扑序较大的可以使得必须选择的点少一些

    由于(tarjan)的性质(col)正好是反向拓扑序,于是如果(i)(col)较小,也就是拓扑序较大,那就优先选择(x_i=1)

    没了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define min(a,b) ((a)<(b)?(a):(b))
    #define re register
    #define maxn 2000005
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt;}e[maxn];
    int n,num,cnt,p,mid,top,m;
    int col[maxn],head[maxn],dfn[maxn],low[maxn],st[maxn],f[maxn];
    inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
    void tarjan(int x) {
    	dfn[x]=low[x]=++cnt;st[++top]=x;f[x]=1;
    	for(re int i=head[x];i;i=e[i].nxt) 
    	if(!dfn[e[i].v]) tarjan(e[i].v),low[x]=min(low[x],low[e[i].v]);
    		else if(f[e[i].v]) low[x]=min(low[x],dfn[e[i].v]);
    	if(low[x]!=dfn[x]) return;++p;
    	do{mid=st[top--];f[mid]=0,col[mid]=p;}while(mid!=x);
    }
    int main() {
    	n=read(),m=read();
    	int x,y,o1,o2;
    	for(re int i=1;i<=m;i++) {
    		x=read(),o1=read(),y=read(),o2=read();
    		if(o1==1) {if(!o2) add(x+n,y+n);else add(x+n,y);}
    		if(o1==0) {if(!o2) add(x,y+n);else add(x,y);}
    		std::swap(x,y),std::swap(o1,o2);
    		if(o1==1) {if(!o2) add(x+n,y+n);else add(x+n,y);}
    		if(o1==0) {if(!o2) add(x,y+n);else add(x,y);}
    	}
    	for(re int i=1;i<=n+n;i++) if(!dfn[i]) tarjan(i);
    	for(re int i=1;i<=n;i++) if(col[i]==col[i+n]) {puts("IMPOSSIBLE");return 0;}
    	puts("POSSIBLE");
    	for(re int i=1;i<=n;i++) printf("%d ",col[i]<col[i+n]);
    	return 0;
    }
    
  • 相关阅读:
    Python动态展示遗传算法求解TSP旅行商问题
    MOEAD算法中均匀权向量的实现---Python
    HDU 5294 多校第一场1007题 最短路+最小割
    POJ 3261 Milk Patterns sa+二分
    HDU 4292 FOOD 2012 ACM/ICPC Asia Regional Chengdu Online
    CodeForces 201A Clear Symmetry
    POJ 1679 The Unique MST 确定MST是否唯一
    POJ 3268 Silver Cow Party 最短路 基础题
    POJ 2139 SIx Degrees of Cowvin Bacon 最短路 水題
    POJ2229 Sumsets 基礎DP
  • 原文地址:https://www.cnblogs.com/asuldb/p/10438324.html
Copyright © 2011-2022 走看看