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

原文地址:https://www.cnblogs.com/ke-xin/p/13583609.html