博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ4945】【NOI2017】游戏(搜索,2-sat)
阅读量:5166 次
发布时间:2019-06-13

本文共 2244 字,大约阅读时间需要 7 分钟。

【NOI2017】游戏(搜索,2-sat)

题面

BZOJ的SPJ是假的

题解

如果没有\(x\)地图的影响

这就是一个裸的\(2-sat\)问题

但是现在有不超过\(8\)\(x\)地图的影响

我们不难想到枚举\(x\)地图的状态再来\(2-sat\)判断剩余是否可行。
这样的复杂度是\(O(3^dn)\),稍微算一下发现这个复杂度有点假

考虑如何优化,我们枚举\(x\)地图不连什么

表面上看起来还是\(O(3^dn)\)
但是,当他等价于\(a,b\)两种地图时,\(2^d\)种方案中一定会包含着最后的解,也就是说,\(a,b\)两种地图替换\(x\)的所有状态,等价于\(a,b,c\)三种地图替换\(x\)
这样的复杂度是\(O(2^dn)\)

现在考虑\(2-sat\)如何连边

对于限制\(i->j\)
显然直接连接\(i->j\)
并且,如果\(j'\)被选择,那么必须选择\(i'\)
所以,同时连接\(j'->i'\)
一些没有意义的连边可以直接省略。

至于输出方案,\(Tarjan\)求出来的强连通分量已经和拓扑序相关,因此没有必要重新建图拓扑排序

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;#define ll long long#define RG register#define MAX 333333inline int read(){ RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t;}char g[MAX];struct Limit{int i,j;char a,b;}q[MAX];int n,D,m,pos[20];struct Line{int v,next;}e[MAX<<3];int h[MAX],cnt;int p[MAX];inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}bool fl;void Build(){ memset(h,0,sizeof(h));cnt=1;fl=true; for(int i=1;i<=n;++i) { p[i]=p[i+n]=p[i+n+n]=0; if(g[i]=='a')p[i+n]=i+n+n,p[i+n+n]=i+n; else if(g[i]=='b')p[i]=i+n+n,p[i+n+n]=i; else p[i]=i+n,p[i+n]=i; } for(int i=1;i<=m;++i) { int u=q[i].i,v=q[i].j; int a=q[i].a-65,b=q[i].b-65; if(u==v&&a==b)continue; if(g[u]-97==a)continue; if(g[v]-97==b){Add(u+a*n,p[u+a*n]);continue;} Add(u+a*n,v+b*n); Add(p[v+b*n],p[u+a*n]); }}int dfn[MAX],low[MAX],S[MAX],top;int gr,G[MAX],tim,ans[MAX];bool Ins[MAX];void Tarjan(int u){ dfn[u]=low[u]=++tim; S[++top]=u;Ins[u]=true; int v; for(int i=h[u];i;i=e[i].next) { v=e[i].v; if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]); else if(Ins[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { ++gr; do{v=S[top--];G[v]=gr;Ins[v]=false;}while(u!=v); }}void Calc(){ Build();gr=tim=0;if(!fl)return; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(G,0,sizeof(G)); for(int i=1;i<=n+n+n;++i)if(!dfn[i])Tarjan(i); for(int i=1;i<=n+n+n;++i)if(G[i]==G[p[i]])return; for(int i=1;i<=n;++i) { if(g[i]=='a')(G[i+n]

转载于:https://www.cnblogs.com/cjyyb/p/8664527.html

你可能感兴趣的文章
Java中反射的学习与理解(一)
查看>>
C语言初学 俩数相除问题
查看>>
B/S和C/S架构的区别
查看>>
[Java] Java record
查看>>
jQuery - 控制元素显示、隐藏、切换、滑动的方法
查看>>
postgresql学习文档
查看>>
Struts2返回JSON数据的具体应用范例
查看>>
js深度克隆对象、数组
查看>>
socket阻塞与非阻塞,同步与异步
查看>>
团队工作第二天
查看>>
System类
查看>>
tableView
查看>>
Happy Great BG-卡精度
查看>>
Xamarin Visual Studio不识别JDK路径
查看>>
菜鸟“抄程序”之道
查看>>
Ubuntu下关闭防火墙
查看>>
TCP/IP 邮件的原理
查看>>
原型设计工具
查看>>
windows下的C++ socket服务器(4)
查看>>
css3 2d转换3d转换以及动画的知识点汇总
查看>>