【BZOJ4945】[Noi2017]游戏

题目描述

题解:2-SAT学艺不精啊!

这题一打眼看上去是个3-SAT?哎?3-SAT不是NPC吗?哎?这题x怎么只有8个?暴力走起!

因为x要么不是A要么不是B,所以直接2^8枚举所有x就行了。然后就变成了一个2-SAT问题。假设有两场游戏1,2,分别可以使用的地图为A1,A2,B1,B2,如果有一个限制是1 A 2 A,那么选A1就必须选A2,然后我这个沙茶就开开心心的拿了55分。

为什么不对?我建出来的图显然不对偶啊!考虑逆否命题,选A1就必须选A2,那么选B2就必须选B1啊!然后跑2-SAT+拓扑排序输出方案即可。

特别地,如果选A1就必须选A2,但是A1不能选,那么我们可以直接无视这个条件。如果选A1就必须选A2,但是A2不能选,那么A1也不能选, 于是就连一条A1->B1的边(你可以理解为这样以来,在反向图中B1的拓扑序在A1前面,所以会先选B1。但真正用意好像不是这个~)。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define P(A,B) ((B-1)*n+A)
using namespace std;
const int maxn=200010;
int n,D,m,sum,tot,top,cnt,flag;
int to[maxn],next[maxn],head[maxn],tt[maxn],nn[maxn],hh[maxn],op[maxn],ot[maxn];
int del[maxn],ins[maxn],dep[maxn],low[maxn],sta[maxn],bel[maxn],pos[10];
int pa[maxn],pb[maxn],pc[maxn],pd[maxn],color[maxn],d[maxn];
char str[maxn],c1[5],c2[5],ans[maxn];
queue<int> q;
void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void ADD(int a,int b)
{
tt[cnt]=b,nn[cnt]=hh[a],hh[a]=cnt++;
}
void tarjan(int x)
{
dep[x]=low[x]=++tot,ins[x]=1,sta[++top]=x;
for(int i=hh[x];i!=-1;i=nn[i])
{
int y=tt[i];
if(!dep[y]) tarjan(y),low[x]=min(low[x],low[y]);
else if(ins[y]) low[x]=min(low[x],dep[y]);
}
if(dep[x]==low[x])
{
int t;
sum++;
do
{
t=sta[top--],ins[t]=0,bel[t]=sum;
}while(t!=x);
}
}
void check()
{
memset(hh,-1,sizeof(hh));
memset(dep,0,sizeof(dep));
cnt=tot=sum=0;
int i,a,b,c;
for(i=1;i<=n;i++)
{
a=(str[i]-'a')*n+i,b=(a-1+n)%(3*n)+1,c=(b-1+n)%(3*n)+1;
del[a]=1,del[b]=del[c]=0;
op[b]=c,op[c]=b;
}
for(i=1;i<=m;i++)
{
a=pc[i]*n+pa[i],b=pd[i]*n+pb[i];
if(a==b||del[a]) continue;
if(pa[i]==pb[i]||del[b])
{
ADD(a,op[a]);
continue;
}
ADD(op[b],op[a]),ADD(a,b);
}
for(i=1;i<=3*n;i++) if(!del[i]&&!dep[i]) tarjan(i);
for(i=1;i<=3*n;i++)
{
if(del[i]) continue;
if(bel[op[i]]==bel[i]) return ;
else ot[bel[op[i]]]=bel[i],ot[bel[i]]=bel[op[i]];
}
flag=1;
}
void dfs(int x)
{
if(x==D+1)
{
check();
return ;
}
str[pos[x]]='a',dfs(x+1);
if(flag) return ;
str[pos[x]]='b',dfs(x+1);
}
void DFS(int x)
{
if(color[x]!=-1) return ;
color[x]=0,color[ot[x]]=1;
for(int i=head[x];i!=-1;i=next[i]) DFS(to[i]);
}
int main()
{
scanf("%d%d%s%d",&n,&D,str+1,&m);
int i,j,u;
for(i=1;i<=n;i++) if(str[i]=='x') pos[++pos[0]]=i;
for(i=1;i<=m;i++)
{
scanf("%d%s%d%s",&pa[i],c1,&pb[i],c2),pc[i]=c1[0]-'A',pd[i]=c2[0]-'A';
}
dfs(1);
if(!flag)
{
printf("-1");
return 0;
}
memset(head,-1,sizeof(head));
memset(color,-1,sizeof(color));
cnt=0;
for(i=1;i<=3*n;i++) if(!del[i])
{
for(j=hh[i];j!=-1;j=nn[j]) if(bel[tt[j]]!=bel[i]) d[bel[i]]++,add(bel[tt[j]],bel[i]);
}
for(i=1;i<=sum;i++) if(!d[i]) q.push(i);
while(!q.empty())
{
u=q.front(),q.pop();
for(i=head[u];i!=-1;i=next[i])
{
d[to[i]]--;
if(!d[to[i]]) q.push(to[i]);
}
if(color[u]!=-1) continue;
DFS(ot[u]);
}
for(i=1;i<=3*n;i++) if(!del[i]&&color[bel[i]]==1) ans[(i-1)%n]=(i-1)/n+'A';
printf("%s",ans);
return 0;
}

最新文章

  1. test「Python」流程&amp;中文
  2. Myeclipse打开是 报:failed to create jvm的解决办法
  3. ural 2062 Ambitious Experiment
  4. Java虚拟机学习(1):体系结构 内存模型
  5. poj2253 最短路 floyd Frogger
  6. 批处理cmd背景颜色
  7. Invoke与BeginInvoke
  8. poj3468 A Simple Problem with Integers(线段树模板 功能:区间增减,区间求和)
  9. 20155304 实验一《Java开发环境的熟悉》实验报告
  10. ssh别名登录密钥登录
  11. Intellij IDEA编译代码出现红色标志
  12. [JSOI2009]密码 [AC自动机]
  13. U盘中的快捷方式解析
  14. 【Android】Android WebView 网页输入框获取焦点
  15. 深入理解Java虚拟机5-chap7-斗者2星
  16. 微信小程序 用户登录 服务器端(TP5.1)实现
  17. 牛客OI周赛4-提高组 C 战争(war)
  18. c# radiobutton
  19. 导致 KEIL error #20 的一种情况
  20. Flyweight模式_Java中23种设计模式

热门文章

  1. 爬虫学习笔记(二)http请求详解
  2. 深入Java数据类型
  3. 第十三届北航程序设计竞赛决赛网络同步赛 B题 校赛签到(建树 + 打标记)
  4. hdu 4823 Energy Conversion 构造
  5. js 拦截全局 ajax 请求
  6. [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene
  7. 【mob】Android短信验证+源码
  8. EasyMvc入门教程-高级控件说明(19)表单控件
  9. Linux学习之十二-Linux文件属性
  10. 2016.7.12 在navicat中用sql语句建表