专栏文章
题解:P10969 Katu Puzzle
P10969题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mir1t517
- 此快照首次捕获于
- 2025/12/04 14:21 3 个月前
- 此快照最后确认于
- 2025/12/04 14:21 3 个月前
题意
有 个点和 条边,给每个点赋值为 或 ,使得每条边满足 。
分析
满足 2-sat 模型,这里不做赘述。
考虑建边,对原有边分类讨论:
可以发现对于 2,3,5,6,都是通过一个变量来推导出另一个变量,而对于 1,4,是直接确定了两个变量的值,是本题的一个难点。
考虑 1,发现当 或 时一定不能成立,于是新建一个节点 ,让 和 连向 ,再让 连向所有点。这样,如果推出 或 ,就一定能推出 ,而 又能推出所有节点,于是成环。4 同理。
考虑判定有无一组解,先判定 是否成立,如果成立则无解;再判定 和 是否至少有一个成立,如果没有则无解(因为如果有一个成立, 就可以取该值而避免冲突)。
code
CPP#include<bits/stdc++.h>
using namespace std;
const int N=205;
char rdc()
{
char c=getchar();
while(c<'A' or c>'Z')c=getchar();
return c;
}
int rd()
{
char c=getchar();
int res=0;
while(!isdigit(c))c=getchar();
while(isdigit(c))res=res*10+c-'0',c=getchar();
return res;
}
vector<int>g[N];
int n,m,T;
int scc[N],num;
int stk[N],tp;
bool instk[N];
int low[N],dfn[N],inx;
void tar(int x) // tarjan 模板
{
if(dfn[x])return;
stk[++tp]=x;
instk[x]=1;
low[x]=dfn[x]=++inx;
for(auto y:g[x])
{
if(!dfn[y])
{
tar(y);
low[x]=min(low[x],low[y]);
}
else if(instk[y])low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
int p;
num++;
do{
p=stk[tp--];
instk[p]=0;
scc[p]=num;
}while(p!=x);
}
}
signed main()
{
n=rd();m=rd();
T=n*2+1;
for(int i=1;i<=n*2;i++)g[T].push_back(i); // T 通向所有点
while(m--)
{
int x=rd()+1,y=rd()+1,c=rd();
char op=rdc();
if(op=='A') // 分类建边
{
if(c==1){
g[x].push_back(T);
g[y].push_back(T);
}
else {
g[x+n].push_back(y);
g[y+n].push_back(x);
}
}
else if(op=='O')
{
if(c==1){
g[x].push_back(y+n);
g[y].push_back(x+n);
}
else {
g[x+n].push_back(T);
g[y+n].push_back(T);
}
}
else {
if(c==1){
g[x].push_back(y+n);
g[x+n].push_back(y);
g[y].push_back(x+n);
g[y+n].push_back(x);
}
else {
g[x].push_back(y);
g[y].push_back(x);
g[x+n].push_back(y+n);
g[y+n].push_back(x+n);
}
}
}
for(int i=1;i<=n*2+1;i++)tar(i);
bool fl=1;
for(int i=1;i<=n;i++)
{
if(scc[i]==scc[i+n] or (scc[i]==scc[T] and scc[i+n]==scc[T])) // 判定有无解,见分析
{
fl=0;
break;
}
}
if(fl)puts("YES");
else puts("NO");
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...