原文链接http://www.cnblogs.com/zhouzhendong/p/8146041.html


题目传送门 - 洛谷3825


题解

  我们考虑到地图中x的个数很少,最多只有8个。

  所以我们可以考虑穷举。

  我们只需要把x变成a和b,这样就涵盖了选择A,B,C的三种情况。

  所以我们状压枚举每一个x可以变成什么情况。

  然后对于每一种情况,几乎就是2-sat裸题了。

  然后我们考虑特殊情况:

  如果选了A就得选择B。

  如果A的状态不合法,那么显然这条边是不用建立的。

  否则:

    如果B的状态不合法,那么显然不可以到达A,于是我们将状态A连向他的对立点。

    如果B的状态合法,那么我们要连接2条边。一条是A到B的,一条是opp(B)到opp(A)的。(其中opp(x)表示状态x的对立状态)

  同学们注意了,Tarjan缩点千万别写错,我已经连续3个程序死在Tarjan缩点上面了。


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
const int N=500005*2,M=1000005*2;
struct Gragh{
int cnt,x[M],y[M],nxt[M],fst[N];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b){
x[++cnt]=a,y[cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g,g2;
int n,m,d,pos[10],w[N][3];
int dfn[N],low[N],vis[N],inst[N],st[N],bh[N],top,time,cnt;
int o[N],in[N],q[N],res[N],head,tail;
char place[N];
struct Limit{
int i,j,hi,hj;
}l[M];
void Get_Pos(){
int cnt=0;
for (int i=1;i<=n;i++)
if (place[i]=='x')
pos[++cnt]=i;
}
int opp(int x){
return x+n*(x<=n?1:-1);
}
void Tarjan_Prepare(){
top=time=cnt=0;
memset(st,0,sizeof st);
memset(bh,0,sizeof bh);
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(vis,0,sizeof vis);
memset(inst,0,sizeof inst);
}
void Tarjan(int x){
dfn[x]=low[x]=++time;
st[++top]=x;
inst[x]=vis[x]=1;
for (int i=g.fst[x];i;i=g.nxt[i])
if (!vis[g.y[i]]){
Tarjan(g.y[i]);
low[x]=min(low[x],low[g.y[i]]);
}
else if (inst[g.y[i]])
low[x]=min(low[x],low[g.y[i]]);
if (dfn[x]==low[x]){
cnt++;
bh[st[top]]=cnt;
inst[st[top]]=0;
while (st[top--]!=x){
bh[st[top]]=cnt;
inst[st[top]]=0;
}
}
}
bool check(){
for (int i=1;i<=n;i++)
if (bh[i]==bh[i+n])
return 0;
else
o[bh[i]]=bh[i+n],o[bh[i+n]]=bh[i];
return 1;
}
void solve(int s){
for (int i=1;i<=d;i++)
place[pos[i]]='a'+((s>>(i-1))&1);
for (int i=1;i<=n;i++){
if (place[i]=='a')w[i][0]=0,w[i][1]=i,w[i][2]=i+n;
if (place[i]=='b')w[i][0]=i,w[i][1]=0,w[i][2]=i+n;
if (place[i]=='c')w[i][0]=i,w[i][1]=i+n,w[i][2]=0;
}
g.clear();
for (int I=1;I<=m;I++){
int i=l[I].i,j=l[I].j,hi=l[I].hi,hj=l[I].hj;
if (!w[i][hi])
continue;
if (w[j][hj]){
g.add(w[i][hi],w[j][hj]);
g.add(opp(w[j][hj]),opp(w[i][hi]));
}
else
g.add(w[i][hi],opp(w[i][hi]));
}
Tarjan_Prepare();
for (int i=1;i<=n*2;i++)
if (!vis[i])
Tarjan(i);
if (!check())
return;
memset(in,0,sizeof in);
g2.clear();
for (int i=1;i<=g.cnt;i++)
if (bh[g.x[i]]!=bh[g.y[i]])
g2.add(bh[g.y[i]],bh[g.x[i]]),in[bh[g.x[i]]]++;
head=tail=0;
for (int i=1;i<=cnt;i++)
if (!in[i])
q[++tail]=i;
memset(res,0,sizeof res);
while (head<tail){
int x=q[++head];
if (!res[x])
res[x]=1,res[o[x]]=-1;
for (int i=g2.fst[x];i;i=g2.nxt[i]){
in[g2.y[i]]--;
if (!in[g2.y[i]])
q[++tail]=g2.y[i];
}
}
for (int i=1;i<=n;i++){
int v=res[bh[i]]==1?i:(i+n),c;
for (int j=0;j<3;j++)
if (w[i][j]==v)
c=j;
printf("%c",c+'A');
}
exit(0);
}
int main(){
scanf("%d%d%s%d",&n,&d,place+1,&m);
for (int i=1;i<=m;i++){
char ch1[3],ch2[3];
scanf("%d%s%d%s",&l[i].i,ch1,&l[i].j,ch2);
l[i].hi=ch1[0]-'A',l[i].hj=ch2[0]-'A';
}
Get_Pos();
for (int i=0;i<(1<<d);i++)
solve(i);
printf("-1");
return 0;
}

  

洛谷3825 [NOI2017]游戏 2-sat的更多相关文章

  1. 洛谷 P3825 [NOI2017]游戏 【2-SAT+状压】

    UOJ和洛谷上能A,bzoj 8ms即WA,现在也不是知道为啥--因为我太弱了 先看数据范围发现d非常小,自然想到了状压. 所以先假装都是只能跑两种车的,这显然就是个2-SAT问题了:对于x场没有hx ...

  2. 洛谷P3825 [NOI2017]游戏(2-SAT)

    传送门 果然图论的题永远建图最麻烦……看着题解代码的建图过程真的很珂怕…… 先不考虑地图$x$,那么每一个地图都只能用两种赛车,于是我们可以用2-SAT来搞,用$i$表示这个地图能用的第一辆车,$i' ...

  3. 洛谷 P2197 nim游戏

    洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...

  4. 洛谷 P1965 转圈游戏

    洛谷 P1965 转圈游戏 传送门 思路 每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,--,依此类推,第n − m号位置上的小伙伴走到第 0 号 ...

  5. 洛谷 P1000 超级玛丽游戏

    P1000 超级玛丽游戏 题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 题目描述 超级玛丽是一个非常经典的游戏.请你用字符画的形式输出超级 ...

  6. 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山

    前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...

  7. $loj10156/$洛谷$2016$ 战略游戏 树形$DP$

    洛谷loj Desription Bob 喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的方法.现在他有个问题. 现在他有座古城堡,古城堡的路形成一棵树.他要在这棵树的节点上放置最少数 ...

  8. 洛谷P1000 超级玛丽游戏(洛谷新手村1-1-1)

    题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 题目描述 超级玛丽是一个非常经典的游戏.请你用字符画的形式输出超级玛丽中的一个场景. *** ...

  9. 洛谷P1080 国王游戏 python解法 - 高精 贪心 排序

    洛谷的题目实在是裹脚布 还编的像童话 这题要 "使得获得奖赏最多的大臣,所获奖赏尽可能的少." 看了半天都觉得不像人话 总算理解后 简单说题目的意思就是 根据既定的运算规则 如何排 ...

随机推荐

  1. ER/数据库建模工具之MySQL Workbench的使用

    参考:https://blog.csdn.net/soulandswear/article/details/60966808 待后续整理...

  2. 连接mysql(建表和删表)

    from sqlalchemy.ext.declarative import declarative_base##拿到父类from sqlalchemy import Column##拿到字段from ...

  3. 走进科学之揭开神秘的"零拷贝"

    前言 "零拷贝"这三个字,想必大家多多少少都有听过吧,这个技术在各种开源组件中都使用了,比如kafka,rocketmq,netty,nginx等等开源框架都在其中引用了这项技术. ...

  4. Confluence 6 通过 SSL 或 HTTPS 运行 - 创建或请求一个 SSL 证书

    在启用 HTTPS 之前,你需要一个有效的证书,如果你已经有了一个有效的证书,你可以直接跳过这个步骤,进入 step 2. 你可以创建一个自签名的证书,或者从信任的 Certificate Autho ...

  5. Confluence 6 手动备份

    Confluence 的 Attachment Storage Configuration 可以配置 Confluence 将附件存储在  home directory,或者是存储在数据库中. Dat ...

  6. flask中的wtforms使用

    一.简单介绍flask中的wtforms WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证. 安装: pip3 install wtforms 二.简单使用wtfo ...

  7. LeetCode(109):有序链表转换二叉搜索树

    Medium! 题目描述: 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: ...

  8. 项目中使用sass预处理器

    安装sass npm install node-sass sass-loader --save 新建样式文件后缀为 .scss 在使用样式的页面引入:import  'xx.scss';

  9. bzoj1123 割点性质应用

    删掉无向图上任意一点,请求出将会增加的不连通的点对数 将无向图联通性的问题转化到搜索树方向上考虑 如果一个点不是割点,那么删掉该点的答案很简单,就是2*(n-1) 如果点u是割点,同时u在搜索树上有t ...

  10. Loadrunner11.0 录制手机App脚本的方法二

    lr11安装一个移动补丁以后,就可以支持抓包文件直接转换为http/html协议的脚本.下面简单说一下过程. 1.工作思路:手机连接可上外网wifi,在手机wifi中设置本机ip的网络地址,然后在本机 ...