[Luogu P3825] [NOI2017] 游戏 (2-SAT)

题面

题面较长,略

分析

看到这些约束,应该想到这是类似2-SAT的问题。但是x地图很麻烦,因为k-SAT问题在k>2的时候是NPC问题,所以不能直接做。

观察到\(d \leq 8\),我们可以直接枚举每个x地图可以让哪些车使用,然后把它转换成标准的2-SAT问题。由于可以用车bc,ac已经覆盖了所有情况,每个x地图只可能是种类A或种类B,枚举的时间复杂度\(2^d\)

对于枚举的每一种情况,我们现在已经得到了每个地图适合哪些车参加,然后考虑建图。

定义若每个地图可以参加的车种类为x和y,第一种车为x,y中字典序较小的,第二种车为字典序较大的。把每个地图拆成两个点,第一个点表示第一种车,第二个点表示第二种车

然后是限制

1.如果限制i的第一个地图\(a_i\)不适合型号为\(x_i\)的车,那么不做任何操作

2.如果限制i的第二个地图\(b_i\)不适合型号为\(y_i\)的车,那么\(a_i\)场不能选\(h_i\),只能选\(x_i\)外符合条件的另一辆车,\(b_i\)场只能选除\(y_i\)外符合条件的另一辆车。两辆车对应的点之间连边即可

3.如果1,2的情况都满足,只需要判断一下可以选的车即可,细节比较复杂,见代码

建完图之后跑2-SAT即可,输出答案的时候注意判断一下这个点对应的车种类到底是A,B还是C

时间复杂度\(O(2^d(n+m))\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#define maxn 100000
using namespace std;
int n,m,d;
char s[maxn+5]; vector<int>E[maxn*2+5];
void add_edge(int u,int v){
E[u].push_back(v);
} int dfn[maxn*2+5];
int low[maxn*2+5];
stack<int>st;
int cnt=0,tim=0;
int bel[maxn*2+5];
bool ins[maxn*2+5];
void tarjan(int x){
dfn[x]=low[x]=++tim;
st.push(x);
ins[x]=1;
for(int y : E[x]){
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}else if(ins[y]){
low[x]=min(low[x],dfn[y]);
}
}
if(low[x]==dfn[x]){
cnt++;
int y;
do{
y=st.top();
st.pop();
ins[y]=0;
bel[y]=cnt;
}while(y!=x);
}
} int cntx;
int all_pos[maxn+5];
int a[maxn+5],b[maxn+5];
char h1[maxn+5],h2[maxn+5];
void ini(){
cnt=0;
tim=0;
for(int i=1;i<=n*2;i++) E[i].clear();
for(int i=1;i<=n*2;i++) dfn[i]=low[i]=bel[i]=ins[i]=0;
while(!st.empty()) st.pop();
}
void make_graph(int bin){
for(int i=1;i<=d;i++){
if(bin&(1<<(i-1))) s[all_pos[i]]='A';
else s[all_pos[i]]='B';
}
for(int i=1;i<=m;i++){
if(h1[i]==s[a[i]]) continue;//第a[i]位不能选h1[i]
else if(h2[i]==s[b[i]]){// 第b[i]位不能选h2[i]
//判断一下当前选的车按字典序是第一辆还是第二辆
if(h1[i]=='C'||(h1[i]=='B'&&s[a[i]]=='C')) add_edge(a[i]+n,a[i]); //规则中选C,或规则中选B且不能选C
else add_edge(a[i],a[i]+n) ;
}else{
int add1,add2;
if(h1[i]=='C'||(h1[i]=='B'&&s[a[i]]=='C')) add1=n;
else add1=0;
if(h2[i]=='C'||(h2[i]=='B'&&s[b[i]]=='C')) add2=n;
else add2=0;
add_edge(a[i]+add1,b[i]+add2);
add_edge(b[i]+n-add2,a[i]+n-add1);
}
}
}
bool check(){
for(int i=1;i<=n*2;i++){
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=n;i++){
if(bel[i]==bel[i+n]) return 0;
}
return 1;
}
void print_ans(){
for(int i=1;i<=n;i++){
if(bel[i]<bel[i+n]){
if(s[i]=='A') putchar('B');//BC的第1个是B
else putchar('A'); //AC或AB的第1个是A
}else{
if(s[i]=='C') putchar('B');//AB的第2个是B
else putchar('C'); //BC或AC的第2个是A
}
}
}
int main(){
char tmp1[2],tmp2[2];
scanf("%d %d",&n,&d);
scanf("%s",s+1);
for(int i=1;i<=n;i++){
if(s[i]=='x'){
cntx++;
all_pos[cntx]=i;
}
s[i]=s[i]-'a'+'A';
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d %s %d %s",&a[i],tmp1,&b[i],tmp2);
h1[i]=tmp1[0];
h2[i]=tmp2[0];
}
for(int bin=0;bin<(1<<d);bin++){
//暴力枚举x是哪一种,注意b,c和a,c就可以覆盖x的三种取值
//所以只要枚举a,b,c
ini();
make_graph(bin);
if(check()){
print_ans();
return 0;
}
}
printf("-1");
}

[Luogu P3825] [NOI2017] 游戏 (2-SAT)的更多相关文章

  1. Luogu P3825 [NOI2017]游戏

    这道题看上去NPC啊,超级不可做的样子. 我们先分析一下简单的情形:没有\(x\)地图 此时每个地图由于限制掉一种汽车,那么显然只会有两种选择. 再考虑到限制的情况,那么大致做法就很显然了--2-SA ...

  2. P3825 [NOI2017]游戏

    题目 P3825 [NOI2017]游戏 做法 \(x\)地图外的地图好做,模型:\((x,y)\)必须同时选\(x \rightarrow y,y^\prime \rightarrow x^\pri ...

  3. Luogu 3825 [NOI2017]游戏

    Luogu的spj现在挂了,要去其他OJ提交. 2-SAT 发现如果不考虑$x$的情况,这就成为一个2-SAT的裸题了,我们有$O(n + m)$的方法可以解决它. 那加上$x$的情况怎么弄……岂不是 ...

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

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

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

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

  6. 并不对劲的bzoj4945:loj2305:uoj317:p3825[NOI2017]游戏

    题目大意 2-SAT,其中有\(d\)(\(d\leq 8\))个点是\(3-SAT\). 题解 枚举\(d\)个点不取三个中(假设三个为\(a,b,c\))的哪一个,然后整体变成做\(2-SAT\) ...

  7. 【BZOJ4945】[Noi2017]游戏 2-SAT

    [BZOJ4945][Noi2017]游戏 题目描述 题解:2-SAT学艺不精啊! 这题一打眼看上去是个3-SAT?哎?3-SAT不是NPC吗?哎?这题x怎么只有8个?暴力走起! 因为x要么不是A要么 ...

  8. [luogu]P1070 道路游戏[DP]

    [luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...

  9. 题解 洛谷 P3825 【[NOI2017]游戏】

    从题面中四元组\((i,h_i,j,h_j)\)限制选择车子型号,不难想到这题要用\(2-SAT\)解决. 考虑转化为\(2-SAT\)模型,发现除地图\(x\)外,其他地图都只有两种车子型号可以参加 ...

随机推荐

  1. 在Wi-Fi路由器中发现了新的安全漏洞

    黑客利用两种互联网通用协议的互动的漏洞:传输控制协议,或TCP和Wi-Fi.该漏洞利用并不针对任何传统的安全漏洞.相反,安全方面的弱点在于20多年前制定的基本Wi-Fi设计决策极难改变. 中国黑客教父 ...

  2. 2018微信小程序开发遇到的坑

    第一个坑:wx.showModal(OBJECT) wx.showModal在安卓手机里,如果点击遮罩的话会关闭弹窗,不会有任何回调.而苹果的情况下则是点击遮罩不会有任何反应. 这样会有什么问题呢? ...

  3. 主席树(静态区间第k大)

    前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建 ...

  4. 又联考了一场,感觉自己好菜啊,T1没写出来,后来花了一个早上调试。QAQ。最后发现是个-1还有取模没打。。。TAT。。。难受极了!!!

    简单的区间(interval) 题目描述: 样例输入: 样例1: 4 3 1 2 3 4 样例2: 4 2 4 4 7 4 样例输出: 样例1: 3 样例2: 6 提示: 时间限制:1000ms 空间 ...

  5. Maven的settings.xml配置详解

    子节点详细介绍转载:http://www.cnblogs.com/jingmoxukong/p/6050172.html?utm_source=gold_browser_extension 全局配置 ...

  6. 算法题常见的BUG错误(总结)

    1. 快排的partition if(l >= r) return ; int i = l, j = r; int tmp = v[i]; while(i < j) { while(i & ...

  7. formdata方式上传文件,支持大文件分割上传

    1.upload.html <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/html"> <h ...

  8. [LOJ2289][THUWC2017]在美妙的数学王国中畅游:Link-Cut Tree+泰勒展开

    分析 又有毒瘤出题人把数学题出在树上了. 根据泰勒展开,有: \[e^x=1+\frac{1}{1!}x+\frac{1}{2!}x^2+\frac{1}{3!}x^3+...\] \[sin(x)= ...

  9. 2018 CCPC 秦皇岛 I (状压DP)

    题意: 首先t组数据  (t<=5),一个n代表有n件东西,每个东西可以代表两个物品,商品或者袋子,每个都有个值,如果这个要代表袋子的话,当前就代表是容量,而且必须把其他几件不是袋子的物品放一些 ...

  10. 文档流&文字&CSS常用命令

    文档流 文档流就是文档内元素流动方向 流动方向 内联元素从左往右流,宽度不够,之字形,且元素会被截断 块元素从上往下流动,一排一排 注意事项 内联元素中有英文单词,流动时宽度不够,英文单词会整体迁移, ...