zoukankan      html  css  js  c++  java
  • 2-sat

    2-sat

    理解

    内含三道例题hdu

    2-sat图具有对称性

    https://wenku.baidu.com/view/9c0afe2b3169a4517723a353.html

    ppt上的题

    和平委员会

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using namespace std;
    const int N=2e6+10; 
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int nxt[N<<1],to[N<<1],tot,hd[N];
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int n,m;
    int dfn[N],low[N],dfn_cnt;
    int st[N],top,scc,col[N];
    bool vis[N];
    void tarjan(int x) {
    	vis[x]=1;
    	st[++top]=x;
    	dfn[x]=low[x]=++dfn_cnt;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(!dfn[y]) {
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    		} else if(vis[y]) low[x]=min(low[x],dfn[y]);
    	}
    	if(low[x]==dfn[x]) {
    		scc++;
    		while(st[top+1]!=x) {
    			col[st[top]]=scc;
    			vis[st[top--]]=0;
    		}
    	}
    }
    int get(int x) {
    	return (x%2)?x+1:x-1;
    }
    int main() {
    	n=read(),m=read();
    	int x,y;
    	for(int i=1;i<=m;i++) {
    		x=read();y=read();
    		add(x,get(y));
    		add(y,get(x));
    	}
    	for(int i=1;i<=2*n;i++)
    		if(!dfn[i]) tarjan(i);
    	for(int i=1;i<=2*n;i++) 
    		if(col[i]==col[get(i)]) {
    			puts("NIE");
    			return 0;
    		}
    	for(int i=1;i<=2*n;i++)
    		if(col[i]>col[get(i)])
    			printf("%d
    ",get(i));
    	return 0;
    }
    

    模板

    同模板:

    https://www.luogu.com.cn/problem/P4171

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N=2e6+10; 
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int nxt[N<<1],to[N<<1],tot,hd[N];
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int n,m;
    int dfn[N],low[N],dfn_cnt;
    int st[N],top,scc,col[N];
    bool vis[N];
    void tarjan(int x) {
    	vis[x]=1;
    	st[++top]=x;
    	dfn[x]=low[x]=++dfn_cnt;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(!dfn[y]) {
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    		} else if(vis[y]) low[x]=min(low[x],dfn[y]);
    	}
    	if(low[x]==dfn[x]) {
    		scc++;
    		while(st[top+1]!=x) {
    			col[st[top]]=scc;
    			vis[st[top--]]=0;
    		}
    	}
    }
    int main() {
    	n=read(),m=read();
    	int a,b,x,y;
    	for(int i=1;i<=m;i++) {
    		a=read(),x=read(),b=read(),y=read();
    		//若选了a=1,则b=0,若b=1,则a=0
    		if(x==0&&y==0) add(a+n,b),add(b+n,a);
    		if(x==1&&y==1) add(b,a+n),add(a,b+n);
    		if(x==1&&y==0) add(a,b),add(b+n,a+n);
    		if(x==0&&y==1) add(a+n,b+n),add(b,a);
    	}
    	for(int i=1;i<=2*n;i++)
    		if(!dfn[i]) tarjan(i);
    	for(int i=1;i<=n;i++) 
    		if(col[i]==col[i+n]) {
    			puts("IMPOSSIBLE");
    			return 0;
    		}
    	puts("POSSIBLE");
    	for(int i=1;i<=n;i++)
    		if(col[i]>col[i+n]) printf("1 ");
    		else printf("0 ");
     //强联通分量编号越小 -> 拓扑序越大  ->越优
    	return 0;
    }
    
    
    

    题目:

    POJ 3207

    POJ 3683

    连边好题

    1 & 0 =0 ,0 & 1 = 0 , 0 & 0 = 0

    1 & 1 =1

    1 or 1 = 1 , 0 or 1 = 1 , 1 or 0 = 1

    0 or 0 =0

    0 ^ 1 =1 , 1 ^ 0 = 1

    1 ^ 1 = 0,0 ^ 0 = 0

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using namespace std;
    const int N=2e6+10; 
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int nxt[N<<1],to[N<<1],tot,hd[N];
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int n,m;
    int dfn[N],low[N],dfn_cnt;
    int st[N],top,scc,col[N];
    bool vis[N];
    void tarjan(int x) {
    	vis[x]=1;
    	st[++top]=x;
    	dfn[x]=low[x]=++dfn_cnt;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(!dfn[y]) {
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    		} else if(vis[y]) low[x]=min(low[x],dfn[y]);
    	}
    	if(low[x]==dfn[x]) {
    		scc++;
    		while(st[top+1]!=x) {
    			col[st[top]]=scc;
    			vis[st[top--]]=0;
    		}
    	}
    }
    int main() {
    	n=read(),m=read();
    	char s[6];
    	for(int i=1;i<=m;i++) {
    		int a=read()+1,b=read()+1,c=read();
    		scanf("%s",s);
    		if(s[0]=='A') {
    			if(c==1) {
    				add(a,a+n),add(b,b+n);
    			} else {
    				add(a+n,b),add(b+n,a);
    			}
    		}
    		if(s[0]=='O') {
    			if(c==1) {
    				add(a,b+n),add(b,a+n);
    			} else {
    				add(a+n,a),add(b+n,b);
    			}
    		}
    		if(s[0]=='X') {
    			if(c==1) {
    				add(a,b+n),add(b,a+n);
    				add(a+n,b),add(b+n,a);
    			} else {
    				add(a+n,b+n),add(b+n,a+n);
    				add(a,b),add(b,a);
    			}
    		}
    	}
    	for(int i=1;i<=2*n;i++)
    		if(!dfn[i]) tarjan(i);
    	for(int i=1;i<=n;i++) 
    		if(col[i]==col[i+n]) {
    			puts("NO");
    			return 0;
    		}
    	puts("YES");
    	return 0;
    }
    
    
    

    Riddle

    对于部分点的连边,暴力是O(N^2)的,

    正解:https://www.luogu.com.cn/blog/lhm126/solution-p6378

    新加一个前缀状态

    详见代码——简直了

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using namespace std;
    const int N=4e6+10; 
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int nxt[N<<1],to[N<<1],tot,hd[N];
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int n,m,k;
    int dfn[N],low[N],dfn_cnt;
    int st[N],top,scc,col[N];
    bool vis[N];
    void tarjan(int x) {
    	vis[x]=1;
    	st[++top]=x;
    	dfn[x]=low[x]=++dfn_cnt;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(!dfn[y]) {
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    		} else if(vis[y]) low[x]=min(low[x],dfn[y]);
    	}
    	if(low[x]==dfn[x]) {
    		scc++;
    		while(st[top+1]!=x) {
    			col[st[top]]=scc;
    			vis[st[top--]]=0;
    		}
    	}
    }
    int pre1[N],pre0[N],a[N];
    int main() {
    	n=read(),m=read();k=read();
    	int x,y;
    	//不加 0, +n 1 选,+2*n 之前不选,+3*n之前选
    	for(int i=1;i<=m;i++) {
    		x=read(),y=read();
    		add(x,y+n),add(y,x+n);
    	}
    	while(k--) {
    		int w=read();
    		for(int i=1;i<=w;i++) 
    			a[i]=read(),add(a[i]+n,a[i]+3*n),add(a[i]+2*n,a[i]);
    	//现在选那么之前必须选,之前不选则现在肯定不能选
    		for(int i=2;i<=w;i++) {
    			add(a[i-1]+3*n,a[i]+3*n);//之前的之前选->之前选
    			add(a[i]+2*n,a[i-1]+2*n);//之前不选->之前的之前也不选
    			add(a[i-1]+3*n,a[i]);//之前的之前选->现在不选
    			add(a[i]+n,a[i-1]+2*n);//现在不选->之前的之前不选
    		}
    	}
    	for(int i=1;i<=4*n;i++)
    		if(!dfn[i]) tarjan(i);
    	for(int i=1;i<=n;i++) 
    		if(col[i]==col[i+n]||col[i+3*n]==col[i+2*n]) {
    			puts("NIE");
    			return 0;
    		}
    	puts("TAK");
    	return 0;
    }
    
    
    

    poj3683wait

      
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int u = 2010, w = 3000010;
    int ver[w], Next[w], head[u], dfn[u], low[u], c[u], s[u], ins[u];
    int val[u], deg[u], opp[u], S[u], T[u], D[u];
    int n, m, tot, num, t, p;
    
    // 原图加边
    void add(int x, int y) {
    	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    
    void tarjan(int x) {
    	dfn[x] = low[x] = ++num;
    	s[++p] = x, ins[x] = 1;
    	for (int i = head[x]; i; i = Next[i])
    		if (!dfn[ver[i]]) {
    			tarjan(ver[i]);
    			low[x] = min(low[x], low[ver[i]]);
    		}
    		else if (ins[ver[i]])
    			low[x] = min(low[x], low[ver[i]]);
    	if (dfn[x] == low[x]) {
    		t++; int y;
    		do { y = s[p--], ins[y] = 0; c[y] = t; } while (x != y);
    	}
    }
    
    bool overlap(int a, int b, int c, int d) {
    	if (a >= c&&a<d || b>c&&b <= d || a <= c&&b >= d) return 1;
    	return 0;
    }
    
    int main() {
    	cin >> n;
    	for (int i = 1; i <= n; i++) 	{
            int sh, sm, th, tm;
    		scanf("%d:%d %d:%d %d", &sh, &sm, &th, &tm, &D[i]);
    		S[i] = sh * 60 + sm; T[i] = th * 60 + tm;
    	}
    	for (int i = 1; i < n; i++)
    		for (int j = i + 1; j <= n; j++) {
                if (overlap(S[i], S[i] + D[i], S[j], S[j] + D[j]))
    				add(i, n + j), add(j, n + i);
                if (overlap(S[i], S[i] + D[i], T[j] - D[j], T[j]))
    				add(i, j), add(n + j, n + i);
                if (overlap(T[i] - D[i], T[i], S[j], S[j] + D[j]))
    				add(n + i, n + j), add(j, i);
                if (overlap(T[i] - D[i], T[i], T[j] - D[j], T[j]))
    				add(n + i, j), add(n + j, i);
            }
    	for (int i = 1; i <= 2 * n; i++)
    		if (!dfn[i]) tarjan(i);
    	for (int i = 1; i <= n; i++) 	{
    		if (c[i] == c[n + i]) { puts("NO"); return 0; }
    		opp[i] = n + i, opp[n + i] = i;
    	}
        puts("YES");
        // 构造方案 
        for (int i = 1; i <= 2 * n; i++)
        	val[i] = c[i] > c[opp[i]];
        // 输出最终结果
    	for (int i = 1; i <= n; i++)
    		if (val[i] == 0) printf("%02d:%02d %02d:%02d
    ",
    			S[i] / 60, S[i] % 60,
    			(S[i] + D[i]) / 60, (S[i] + D[i]) % 60);
    		else printf("%02d:%02d %02d:%02d
    ",
    			(T[i] - D[i]) / 60, (T[i] - D[i]) % 60,
    			T[i] / 60, T[i] % 60);
    	return 0;
    }
    
    

    POJ 3648

    POJ 2723

    POJ 2749

    难题:

    游戏

    [ZJOI2016] 旅行者

    小结

    https://wenku.baidu.com/view/afd6c436a32d7375a41780f2.html

    https://wenku.baidu.com/view/0f96c3daa58da0116c1749bc.html

  • 相关阅读:
    Vue 目录
    【SVN】彻底 svn 服务器上的 删除某一个文件或文件夹
    【Linux】安装 PostgreSQL
    【Linux】安装 node.js
    在vue中使用echarts图表
    Grunt搭建自动化web前端开发环境--完整流程
    JavaScript 开发规范
    React设计思想
    js闭包的理解
    pytharm安装第三方库
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13583609.html
Copyright © 2011-2022 走看看