[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. Flask【第7篇】:Flask中的wtforms使用

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

  2. 2016.5.21【初中部 NOIP提高组】模拟赛A​ 总结

    这次比赛的题目看上去好像不难,但当开始仔细想的时候才发现,并没有那么简单. T1旅行:刚开始看到k<=4的时候还以为有题可以AC了,不过呢,还是毫无思路. T3Pty爬山:雨天的尾巴最近打了几道 ...

  3. telnet ip 端口

    telnet ip 端口 1.关闭防火墙, 2.配置防火墙,出入端规则

  4. layui jquery ajax,url,type,async,dataType,data

    $.ajax({ url: '/foensys/user/userDelete/'+data[0].id, type:"get", async:true, dataType:&qu ...

  5. 【bzoj1324】Exca王者之剑(8-9 方格取数问题)

    *题目描述: 在一个有m*n (m,n<=100)个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法, ...

  6. spring学习笔记之---JDBC Template

    JDBC  Template(简化持久化操作) (一)创建项目 (1)Maven配置 <dependencies> <dependency> <groupId>ju ...

  7. ES的副本数量、插入大批量数据前,副本数应该设置为0

    多副本可以提升检索的能力,但是如果副本数量太多,插入数据的时候容易出现卡顿现象: 因为主分片要把数据同步给所有的副本,所以建议副本数量最好是1-2个: ---- Es在索引数据的时候,如果存在副本,那 ...

  8. View 层

    package com.test.mvp.mvpdemo.mvp.v1.view; import android.app.ProgressDialog;import android.os.Bundle ...

  9. 大型网站技术架构,4网站的高性能架构之Web前端性能优化

    一般说来Web前端指网站业务逻辑之前的部分,包括浏览器加载.网站视图模型.图片服务.CDN服务等,主要优化手段有优化浏览器访问.使用反向代理.CDN等. 4.2.1 浏览器访问优化 1.减少http请 ...

  10. fedora18 You might need to install dependency packages for libxcb.

    22 down vote The page Qt for X11 Requirements lists some packages required to build Qt on Debian. Th ...