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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具