ybtoj Au 2-SAT问题
前言中的前言
-
由于本人过菜,有些题解会咕掉,请原谅这个蒟蒻
-
由于本人过菜,不知道什么时候就
了,想给这个机房留下点什么…… -
如果想看高效进阶的题解,建议出门左拐,去云落那里看看,保证是全网最全最好的,但不要对云落的博客好奇,更不要看云落的一言 和 云落的合集:黑夜刀己,白日爱人
-
本篇题解是在作者极困的情况下写的(楞一下神就会睡着那种),如有错误,应评论/私信,谢谢各位
正片开始!
好耶!!!(泪目)
题面
前言
2-SAT T1,板子题
正文
首先明确一个事情:不选夫就相当于选妻,不选妻就相当于选夫
好的
那么我们用
那么,如果两个人是仇恨关系,那么
如果
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e6+6;
int n,m,head[N<<1],cnt;
struct node{int to,nxt;}e[N<<1];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int dfn[N],low[N],tim,st[N],top,c[N],tot;
void tarjan(int x){
dfn[x]=low[x]=++tim;
st[++top]=x;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(!c[y]){
low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
c[x]=++tot;
while(st[top]!=x){
c[st[top--]]=tot;
}
top--;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int p=0;
while(cin>>n>>m){
p++;
cnt=top=0;
for(int i=1;i<=N<<1-5;i++)head[i]=c[i]=dfn[i]=low[i]=0;
for(int i=1;i<=m;i++){
int a1,a2,c1,c2;
cin>>a1>>a2>>c1>>c2;
a1=(a1<<1)+c1;
a2=(a2<<1)+c2;
add(a1,a2^1);
add(a2,a1^1);
}
for(int i=0;i<n<<1;i++){
if(!dfn[i])tarjan(i);
}
bool flag=1;
for(int i=0;i<n;i++){
if(c[i<<1]==c[(i<<1)^1])flag=0;
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
后记
小学妹已经三天没来力
题面
前言
2-SAT T2,水题
正文
用
那么,如果矛盾,就连
代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,head[N<<1],cnt;
struct node{int to,nxt;}e[N<<1];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int dfn[N],low[N],c[N],st[N],tim,top,tot;
void tarjan(int x){
dfn[x]=low[x]=++tim;
st[++top]=x;
for(int i=head[x];~i;i=e[i].nxt){
int y=e[i].to;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(!c[y]){
low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
c[x]=++tot;
while(st[top]!=x){
c[st[top--]]=tot;
}
top--;
}
}
bool flag;
int main(){
while(1){
cin>>n>>m;
if(!n)return 0;
flag=1;
// for(int i=1;i<=n;i++){
// add(i<<1,i<<1|1);
// add(i<<1|1,i<<1);
// }
for(int i=0;i<=N-5;i++)dfn[i]=low[i]=c[i]=0;
top=tot=tim=cnt=0;
for(int i=0;i<=(N<<1)-5;i++)head[i]=-1;
for(int i=1;i<=m;i++){
int o,o1;char op,op1;cin>>o>>op>>o1>>op1;
//cout<<o<<op<<o1<<op1<<endl;
o=o*2+(op=='h'?1:0);
o1=o1*2+(op1=='h'?1:0);
add(o,o1^1),add(o1,o^1);
//cout<<o<<" "<<o1<<endl;
}
add(0,1);
for(int i=0;i<=n*2-1;i++){
if(!dfn[i]){
tarjan(i);
}
}
for(int i=0;i<n;i++){
if(c[i<<1]==c[i<<1|1]){
flag=0;
cout<<"bad luck"<<endl;
break;
}
}
if(flag){
for(int i=1;i<n;i++){
cout<<i;
if(c[i<<1|1]>c[i<<1])cout<<"h ";
else cout<<"w ";
}
cout<<endl;
}
}
return 0;
}
后记
多测!可恶的多测!!!
题面
前言
2-SAT T3,大水题
正文
只一个‘大’字是我对他最大的宽容
前半部分用 2-SAT 板子
关键是怎么求 NY?(怎么que我笔名)
好的
我们发现
可以
于是我们
然后过了
然后我们惊奇的发现
前面的
代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e4+4;
int n,m,head[N<<1],cnt;
struct node{int to,nxt;}e[N<<1];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int dfn[N],low[N],c[N],st[N],top,tot,tim;
void tarjan(int x){
dfn[x]=low[x]=++tim;
st[++top]=x;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}else if(!c[y]){
low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
c[x]=++tot;
while(st[top]!=x){
c[st[top--]]=tot;
}
top--;
}
}
int vis[N];
void dfs(int x,int il){
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(vis[y]!=il){vis[y]=il;dfs(y,il);}
}
}
int opp;
bool check(int x){
vis[x]=++opp;
//if(x==4)cout<<opp;
dfs(x,opp);
for(int i=1;i<=n;i++){
if(vis[i<<1]==opp&&vis[i<<1|1]==opp)return 0;
}
return 1;
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int o,o1;char op,op1;
cin>>o>>op>>o1>>op1;
o=o*2+(op=='Y');
o1=o1*2+(op1=='Y');
add(o^1,o1);
add(o1^1,o);
//cout<<(o^1)<<" "<<o1<<endl;
//cout<<(o1^1)<<" "<<o<<endl;
}
for(int i=2;i<=2*n+1;i++){
if(!dfn[i])tarjan(i);
}
for(int i=1;i<=n;i++){
if(c[i<<1]==c[i<<1|1]){cout<<"IMPOSSIBLE"<<endl;return 0;}
}
for(int i=1;i<=n;i++){
bool f1,f2;
f1=check(i<<1|1);
f2=check(i<<1);
if(f1&&f2)cout<<"?";
else if(f1)cout<<"Y";
else cout<<"N";
}
return 0;
}
后记
无语……
题面
前言
2-SAT T4,数学题?
正文
首先题意是让你判断这个图是不是平面图
平面图性质:
-
m<=3*n-6
-
如果环上两条线段的端点是交错的:
那么需要一条在环里,一条在环外
好的
那么我们直接把
2-SAT
代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e6+6;
int t,n,m,id[N],cir[205][205],d[N],cnt1,head[N<<1],cnt;
struct Node{int x,y;}e1[N],E[N];
struct node{int to,nxt;}e[N<<1];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int dfn[N],c[N],low[N],tot,tim,top,st[N];
void tarjan(int x){
dfn[x]=low[x]=++tim;
st[++top]=x;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}else if(!c[y]){
low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
c[x]=++tot;
while(st[top]!=x){
c[st[top--]]=tot;
}
top--;
}
}
int main(){
cin>>t;
while(t--){
tot=top=cnt=cnt1=tim=0;
for(int i=1;i<=N-5;i++){
dfn[i]=low[i]=c[i]=0;
}
for(int i=1;i<=N*2-5;i++)head[i]=0;
memset(cir,0,sizeof(cir));
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>e1[i].x>>e1[i].y;
if(e1[i].x>e1[i].y)swap(e1[i].x,e1[i].y);
}
for(int i=1;i<=n;i++){
cin>>d[i];
//cout<<d[i]<<" ";
id[d[i]]=i;
if(i>1){
int x=d[i-1],y=d[i];
if(x<y)cir[x][y]=1;
else cir[y][x]=1;
}
}
if(m>3*n-6){cout<<"NO"<<endl;continue;}
int x=d[n],y=d[1];
if(x<y)cir[x][y]=1;
else cir[y][x]=1;
for(int i=1;i<=m;i++){
if(cir[e1[i].x][e1[i].y])continue;
E[++cnt1].x=e1[i].x,E[cnt1].y=e1[i].y;
}
for(int i=1;i<cnt1;i++){
for(int j=i+1;j<=cnt1;j++){
int u=id[E[i].x],v=id[E[i].y],x=id[E[j].x],y=id[E[j].y];
if (u > v) swap(u, v); if (x > y) swap(x, y);
if((u<x&&x<v&&v<y)||(x<u&&u<y&&y<v)){
add(i,j+m),add(i+m,j),add(j,i+m),add(j+m,i);
}
}
}
for(int i=1;i<=m<<1;i++){
if(!dfn[i])tarjan(i);
}
bool flag=1;
for(int i=1;i<=m;i++){
if(c[i]==c[i+m])flag=0;
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
后记
云落:要早睡早起
我的生物钟:好
然后
2:20 醒了……
题面
前言
2-SAT T5,应用题
正文
这里把两个中转站当作 2-SAT 是显然的
二分也是显然的
问题是怎么处理距离
总的来说
如果距离超了,就不能走,也就是在 2-SAT 上连反点
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+6;
int n,a[N],b[N],c[N],d[N],A,B,sx1,sy1,sx2,sy2,x[N],y[N],dis[N],len;
int Dis(int x,int y,int x1,int y1){
return abs(x-x1)+abs(y-y1);
}
int tot,top,tim,dfn[N],low[N],c1[N],st[N],head[N*N*2],cnt;
struct node{int to,nxt;}e[N*N*2];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void tarjan(int x){
dfn[x]=low[x]=++tim;
st[++top]=x;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}else if(!c1[y]){
low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
c1[x]=++tot;
while(st[top]!=x){
c1[st[top--]]=tot;
}
top--;
}
}
bool check(int mid){
for(int i=1;i<=N-5;i++){
dfn[i]=low[i]=c1[i]=0;
}
for(int i=1;i<=N*N*2-5;i++)head[i]=0;
cnt=tot=top=tim=0;
for(int i=1;i<=A;i++){
add(a[i],b[i]+n),add(b[i],a[i]+n),add(a[i]+n,b[i]),add(b[i]+n,a[i]);
}
for(int i=1;i<=B;i++){
add(c[i],d[i]),add(c[i]+n,d[i]+n),add(d[i],c[i]),add(d[i]+n,c[i]+n);
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(dis[i]+dis[j]>mid)add(i,j+n),add(j,i+n);
if(dis[i+n]+dis[j+n]>mid)add(i+n,j),add(j+n,i);
if(dis[i+n]+dis[j]+len>mid)add(i+n,j+n),add(j,i);
if(dis[i]+dis[j+n]+len>mid)add(i,j),add(j+n,i+n);
}
}
for(int i=1;i<=2*n;i++){
if(!dfn[i])tarjan(i);
}
for(int i=1;i<=n;i++){
if(c1[i]==c1[i+n])return 0;
}
return 1;
}
int main(){
while(cin>>n>>A>>B){
cin>>sx1>>sy1>>sx2>>sy2;
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
dis[i]=Dis(x[i],y[i],sx1,sy1);
dis[i+n]=Dis(x[i],y[i],sx2,sy2);
}
len=Dis(sx1,sy1,sx2,sy2);
for(int i=1;i<=A;i++){
cin>>a[i]>>b[i];
}
for(int i=1;i<=B;i++){
cin>>c[i]>>d[i];
}
int l=0,r=8000006,ans=-1;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid))r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans<<endl;
}
return 0;
}
后记
玩完原神瞬间调出来力
题面
前言
2-SAT T6,毒瘤题
正文
本蒟蒻没有调出来……
代码
#include<iostream>
#include<cstring>
#define ch getchar
#define in getint
#define ts timestamp
#define ins in_stack
using namespace std;
const int N=100010,M=200010;
int n,d,m;
char s[N];
int h[N],e[M],ne[M],idx;
int dfn[N],low[N],timestamp;
int stk[N],top;
bool in_stack[N];
int id[N],cnt;
int pos[10];
struct Op
{
int x,y;
char a,b;
}op[M];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int in(int x,char b,int t)
{
char a=s[x]-'a';
b-='A';
if(((a+1)%3!=b)^t) return x+n;
return x;
}
char ch(int x,int t)
{
int y=s[x]-'a';
return 'A'+(y+3+(t? -1 :1))%3;
}
void tarjan(int u)
{
dfn[u]=low[u]=++ts;
stk[++top]=u,ins[u]=true;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(ins[j])
low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
cnt++;
int y;
do{
y=stk[top--];
ins[y]=false;
id[y]=cnt;
} while(y!=u);
}
}
bool launch()
{
memset(h,-1,sizeof h);
memset(dfn,0,sizeof dfn);
idx=ts=cnt=0;
for(int i=0;i<m;i++)
{
int x=op[i].x-1,y=op[i].y-1;
char a=op[i].a,b=op[i].b;
if(s[x]!=a-'A'+'a')
{
if(s[y]!=b-'A'+'a') add(in(x,a,0),in(y,b,0)),add(in(y,b,1),in(x,a,1));
else add(in(x,a,0),in(x,a,1));
}
}
for(int i=0;i<n*2;i++)
if(!dfn[i])
tarjan(i);
for(int i=0;i<n;i++)
if(id[i]==id[i+n])
return false;
for(int i=0;i<n;i++)
if(id[i]<id[i+n]) printf("%c",ch(i,0));
else printf("%c",ch(i,1));
return true;
}
int main()
{
scanf("%d%d%s",&n,&d,s);
for(int i=0,j=0;i<n;i++)
if(s[i]=='x')
pos[j++]=i;
scanf("%d",&m);
for(int i=0;i<m;i++) scanf("%d %c %d %c",&op[i].x,&op[i].a,&op[i].y,&op[i].b);
for(int k=0;k<1<<d;k++)
{
for(int i=0;i<d;i++)
if(k>>i&1) s[pos[i]]='a';
else s[pos[i]]='b';
if(launch()) return 0;
}
puts("-1");
return 0;
}
后记
我们,开摆!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】