2-SAT问题

类似于有m个条件,每个条件里面有两个元素互相约束,最后判断存不存在满足所有条件元素的问题。

可以将条件之中的约束转化成边,元素就是点。
A -> B代表如果满足A,那么必须满足B。

用tarjan进行缩点,如果两个点所代表的元素是矛盾的,说明没有解。

对于一个元素只有两种可能的问题时

A -> B等价于!B -> !A所以强连通分量前后各是一种答案,我们统一取拓扑序大的或者拓扑序小的就可以了。

解释得潦草而且不严谨,谨慎阅读

「模板」2-SAT 问题

#include <bits/stdc++.h>
using namespace std;
const int N = 2000005;
vector<int> g[N];
int n, m, dfn[N], scc_cnt = 0, scc[N], cnt = 0, q[N], times = 0, low[N], vis[N];
void tarjan(int x)
{
	dfn[x] = low[x] = ++ times, q[++ cnt] = x,vis[x] = true; 
	for (int i = 0; i < g[x].size(); ++ i)
	{
		int y = g[x][i];
		if(!dfn[y])
		{
			tarjan(y);
			low[x] = min(low[x], low[y]);	
		} 
		else if(vis[y]) low[x] = min(low[x], low[y]);
	}
	if(low[x] == dfn[x])
	{
		scc_cnt ++;
		int p;
		do
		{
			p = q[cnt --];
			vis[p] = 0;
			scc[p] = scc_cnt;
		}while(p != x);
	}
	return ;
} 
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; ++ i)
	{
		int a, b, c;
		char op[5];
		scanf("%d %d %d %s", &a, &b, &c, op + 1);
		a --, b --;
		if(op[1] == 'O')
		{
			if(c == 0) g[a << 1 | 1].push_back(a << 1), g[b << 1 | 1].push_back(b << 1);
			else g[a << 1].push_back(b << 1 | 1), g[b << 1].push_back(a << 1 | 1);
		} 
		else if(op[1] == 'X')
		{
			if(c == 0) g[a << 1].push_back(b << 1), g[b << 1].push_back(a << 1), g[a << 1 | 1].push_back(b << 1 | 1), g[b << 1 | 1].push_back(a << 1 | 1);
			else g[a << 1].push_back(b << 1 | 1), g[b << 1 | 1].push_back(a << 1), g[a << 1 | 1].push_back(b << 1), g[b << 1].push_back(a << 1 | 1); 
		}
		else 
		{
			if(c == 0) g[a << 1 | 1].push_back(b << 1), g[b << 1 | 1].push_back(a << 1);
			else g[a << 1].push_back(a << 1 | 1), g[b << 1].push_back(b << 1 | 1);
		}
	}
	for (int i = 0; i < n * 2; ++ i) if(!dfn[i]) tarjan(i);
	for (int i = 0; i < n; ++ i)
	{
		if(scc[i << 1] == scc[i << 1 | 1]) 
		{
			printf("IMPOSSIBLE");
			return 0;
		}
	} 
	printf("POSSIBLE\n");
	for (int i = 0; i < n; ++ i) 
	{
		if(scc[i << 1] < scc[i << 1 | 1]) printf("0 ");
		else printf("1 ");
	}
	return 0;
}

牧师约翰最忙碌的一天

#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, m;
char s[10];
vector<int> g[N];
int get_time()
{
	return (s[1] - '0') * 600 + (s[2] - '0') * 60 + (s[4] - '0') * 10 + (s[5] - '0');
}
void turn(int x)
{
	printf("%c%c", x / 60 / 10 + '0', x / 60 % 10 + '0');
	printf(":");
	printf("%c%c", x % 60 / 10 + '0', x % 60 % 10 + '0');
	return ; 
}
struct node
{
	int l, r, d;
}p[N], P[N];
bool jiao(int a, int b, int x, int y)
{
	if(a <= x && x < b) return true;
	if(x <= a && a < y) return true;
	return false; 
}
int dfn[N], low[N], tot = 0, scc_cnt = 0, scc[N];
stack<int> q;
bool vis[N];
void dfs(int x)
{
	low[x] = dfn[x] = ++ tot, q.push(x), vis[x] = 1;
	for (int i = 0; i < g[x].size(); ++ i)
	{
		int y = g[x][i];
		if(!dfn[y])
		{
			dfs(y);
			low[x] = min(low[x], low[y]);
		}
		else if(vis[y]) low[x] = min(low[x], low[y]);
	}
	if(low[x] == dfn[x])
	{
		int y;
		scc_cnt ++;
		do
		{
			y = q.top(); q.pop();
			scc[y] = scc_cnt;
			vis[y] = 0; 
			
		}while(y != x);
	}
	return ;
}
bool cmp(node a, node b)
{
	return a.l < b.l;
}
int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; ++ i)
	{
		scanf("%s", s + 1);
		p[i].l = get_time();
		scanf("%s", s + 1);
		p[i].r = get_time();
		scanf("%d", &p[i].d);
	}
	bool pd = true;
	for (int i = 0; i < n; ++ i)
	{
		for (int j = 0; j < n; ++ j)
		{
			if(i == j) continue;
			bool pd1 = jiao(p[i].l, p[i].l + p[i].d, p[j].l, p[j].l + p[j].d);
			bool pd2 = jiao(p[i].l, p[i].l + p[i].d, p[j].r - p[j].d, p[j].r);
			if(pd1 && !pd2)  g[i << 1].push_back(j << 1 | 1), g[j << 1].push_back(i << 1 | 1);
			if(!pd1 && pd2) g[i << 1].push_back(j << 1), g[j << 1 | 1].push_back(i << 1 | 1);
			bool pd3 = jiao(p[i].r - p[i].d, p[i].r, p[j].l, p[j].l + p[j].d);
			bool pd4 = jiao(p[i].r - p[i].d, p[i].r, p[j].r - p[j].d, p[j].r);
			if(pd3 && !pd4) g[i << 1 | 1].push_back(j << 1 | 1), g[j << 1].push_back(i << 1);
			if(!pd3 && pd4) g[i << 1 | 1].push_back(j << 1), g[j << 1 | 1].push_back(i << 1);
			if(pd3 && pd4 && pd1 && pd2) {pd = false; break; }
		}
		if(!pd) break;
	}
	if(!pd) 
	{
		printf("NO");
		return 0;
	}
	for (int i = 0; i < n + n; ++ i) if(!dfn[i]) dfs(i);
	for (int i = 0; i < n; ++ i)
	{
		if(scc[i << 1] == scc[i << 1 | 1]) {pd = false; break; }
	}
	if(!pd)
	{
		printf("NO");
		return 0;
	}
	printf("YES\n");
	for (int i = 0; i < n; ++ i)
	{
		if(scc[i << 1] < scc[i << 1 | 1]) P[i].l = p[i].l, P[i].r = p[i].l + p[i].d;
		else P[i].l = p[i].r - p[i].d, P[i].r = p[i].r;
	}
	sort(P, P + n, cmp);
	for (int i = 0; i < n; ++ i)
	{
		turn(P[i].l);
		putchar(' ');
		turn(P[i].r);
		putchar('\n');
	}
	return 0;
}

游戏

由于d非常的小,如果每一个点只有两种选择的话,那么就是一个标准的2-SAT问题。对于x场地来说,选择a、b或者c。如果x分别为A场地和B场地就可以涵盖这三种情况。所以我们暴力枚举x场地,使它成为A场地或者B场地。

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, d, dfn[N], tot = 0, low[N], scc_cnt = 0, scc[N], fx[15];
bool opt = false, flag[N];
stack<int> q;
char s[N], vis[15], c1[125][2], c2[125], c3[125][125];
struct request
{
	int x, y;
	char a, b;
}p[N];
vector<int> g[N];
void init()
{
	c1['a'][0] = 'B', c1['a'][1] = 'C', c1['b'][0] = 'A', c1['b'][1] = 'C', c1['c'][0] = 'A', c1['c'][1] = 'B';
	c3['a']['B'] = 0, c3['a']['C'] = 1, c3['b']['A'] = 0, c3['b']['C'] = 1, c3['c']['A'] = 0, c3['c']['B'] = 1;
	c2['a'] = 'A', c2['b'] = 'B', c2['c'] = 'C', c2['A'] = 'a', c2['B'] = 'b', c2['C'] = 'c';
	return ; 
}
void tarjan(int x)
{
	dfn[x] = low[x] = ++ tot, flag[x] = 1, q.push(x);
	for (int  i = 0 ; i < g[x].size(); ++ i)
	{
		int y = g[x][i];
		if(!dfn[y]) 
		{
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if(flag[y]) low[x] = min(low[x], low[y]);
	}
	if(low[x] == dfn[x])
	{
		int y;
		scc_cnt ++;
		do
		{
			y = q.top(); q.pop();
			flag[y] = 0;
			scc[y] = scc_cnt;
		}while(y != x);
	}
}
void dfs(int x)
{
	if(opt) return ;
	if(x == d + 1)
	{
		for (int j = 1; j <= d; ++ j) s[fx[j]] = vis[j];
		scc_cnt = 0, tot = 0;
		for (int  i = 0; i < n + n; ++ i) dfn[i] = low[i] = flag[i] = scc[i] = 0, g[i].clear();
		for (int i = 1; i <= m; ++ i)
		{
			if(s[p[i].x] == c2[p[i].a]) continue;
			if(s[p[i].y] == c2[p[i].b]) 
			{
				int y = c3[s[p[i].x]][p[i].a];
				g[p[i].x << 1 | y].push_back(p[i].x << 1 | (y ^ 1));
			}
			else
			{
				int a = c3[s[p[i].x]][p[i].a], b = c3[s[p[i].y]][p[i].b];
				g[p[i].x << 1 | a].push_back(p[i].y << 1 | b);
				g[p[i].y << 1 | (b ^ 1)].push_back(p[i].x << 1 | (a ^ 1)); 
			}
		}
		bool pd = true;
		
		for (int i = 0; i < n + n; ++ i) if(!dfn[i]) tarjan(i);
		for (int i = 0; i < n; ++ i)
		{
			if(scc[i << 1] == scc[i << 1 | 1]) {pd = false; break; }
		}
		if(!pd) return ;
		opt = true;
		for (int i = 0; i < n; ++ i)
		{
			if(scc[i << 1] < scc[i << 1 | 1]) printf("%c", c1[s[i]][0]);
			else printf("%c", c1[s[i]][1]);
		}
		return ;
	}
	vis[x] = 'a';
	dfs(x + 1);
	vis[x] = 'b';
	dfs(x + 1);
}
int main()
{
	init();
	scanf("%d %d", &n, &d);
	scanf("%s", s);
	for (int i = 0, j = 1; i < n; ++ i)
	{
		if(s[i] == 'x') fx[j] = i, j ++;
	}
	scanf("%d", &m);
	for (int i = 1; i <= m; ++ i)
	{
		char str[2];
		scanf("%d %s", &p[i].x, str);
		p[i].a = str[0];
		scanf("%d %s", &p[i].y, str);
		p[i].b = str[0];
		p[i].x --, p[i].y --;
	}
	dfs(1);
	if(opt == false) printf("-1");
	return 0;
}
posted @   Helioca  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
Document
点击右上角即可分享
微信分享提示