【BZOJ4945】[Noi2017]游戏 2-SAT

【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;
}
时间: 2024-10-12 17:42:49

【BZOJ4945】[Noi2017]游戏 2-SAT的相关文章

BZOJ4945 NOI2017 游戏 - 2-SAT

这题放在NOI里应该不算难的吧--但是细节比较多,所以写起来会有点** 题目限定了道路不能通行某种车辆,也就是可以通行两种车辆 我们将这两种车辆分别作为正点和反点进行约束就可以了 建图较为容易 最后将所有的x枚举一下即可 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #inclu

【uoj#317】[NOI2017]游戏 2-SAT

题目描述 给出 $n$ 个赛车赛道和A.B.C三种赛车,除了 $d$ 个赛道可以使用所有三种赛车以外每个都只能使用给出的两种之一.另外给出 $m$ 条限制:某个赛道使用X则某另一个赛道必须使用Y.问:是否存在一种方案满足所有条件?输出一种合法方案. $n]le 50000,d\le 8,m\le 100000$ . 题解 2-SAT 3-SAT是NP完全问题,由于 $d$ 只有 $8$ ,因此考虑枚举每个万能位置的取值,转化为2-SAT问题. 那么对于一条限制,显然描述对应着一条边:另外一个命题

【题解】NOI2017游戏

2-SAT.洛谷P3845 一开始以为--怎么有3个呢?后来发现因为每个地图都有一种车是不能用的,所以就等于每一个地图都有两个适应的车啦. 那么对于x类型的地图呢--只有8个,直接2^8暴力枚举每一种可能,就转化为了普通的问题. 令u,u'分别为一个地图适应的两种车,那么对于一个要求h1 - d1, h2 - d2而言,如果第一个既不是u,也不是u',说明可以无视:如果第二个都不能满足, 就连d1 - d1',表示如果必须选第一辆,问题无解.其余情况则d1-d2,d2'-d1'(重要!保证图的对

[NOI2017]游戏

Sol 然而我的代码在\(UOJ\)上被\(hack\)\(\ TLE\)了 但思路是没问题的\(TAT\) 如果没有\(x\),就是个\(2-SAT\) 我们爆搜\(x\)的地图是\(a\)还是\(b\)就好了 不用枚举它是\(c\),枚举\(a\),\(b\)就能保证正好选\(ABC\)三种车 我也不知道我的输出方案哪里学的 拓扑排序+染色\(QAQ\) 如果觉得自己的代码优秀就去\(UOJ\)上交吧(逃 # include <bits/stdc++.h> # define RG regi

loj2305 noi2017 游戏

题目链接 思路 既然\(x\)的数量那么小,我们就可以先把每个\(x\)搜索一遍. 枚举x的时候不需要把\(a,b,c\)全枚举一遍,只要枚举其中的两个就可以枚举到当前位置选任何车的情况. 然后就变成了只有\('a','b','c'\)的序列.寻找满足题目要求的方案. \(2-sat\)模型. 连边的时候注意一些技巧,否则\(if\)写到自闭.. 在\(UOJ\)上会被卡掉\(3\)分.实在懒得去卡常了233 代码 /* * @Author: wxyww * @Date: 2019-04-29

Luogu P4782 【模板】2-SAT 问题(2-SAT)

P4782 [模板]2-SAT 问题 题意 题目背景 \(2-SAT\)问题模板 题目描述 有\(n\)个布尔变量\(x_1\sim x_n\),另有\(m\)个需要满足的条件,每个条件的形式都是"\(x_i\)为\(true/false\)或\(x_j\)为\(true/false\)".比如"\(x_1\)为真或\(x_3\)为假"."\(x_7\)为假或\(x_2\)为假".\(2-SAT\)问题的目标是给每个变量赋值使得所有条件得到满足.

【NOI2017】游戏 2-sat算法

[题目]LibreOJ [题意]n场游戏,有三种车ABC,给定长度为n的字符串,'a'表示不能选A,'b''c'同理,'x'表示不限,至多d个'x'.有m个限制(i,hi,j,hj)表示如果第i场选择车hi,那么第j场必须选择车hj.求可行方案,或无解.n<=10^5,d<=8. [算法]2-sat [题解] 原文地址:https://www.cnblogs.com/onioncyc/p/8605676.html

漫谈游戏中的人工智能

写在前面   今天我们来谈一下游戏中的人工智能.当然,内容可能不仅仅限于游戏人工智能,还会扩展一些其他的话题. 游戏中的人工智能,其实还是算是游戏开发中有点挑战性的模块,说简单点呢,是状态机,说复杂点呢,是可以帮你打开新世界大门的一把钥匙.有时候看到知乎上一些可能还是前公司同事的同学的一些话,感觉还是挺哭笑不得的,比如这篇:http://zhi.hu/qu1h,吹捧机器学习这种玄学,对游戏开发嗤之以鼻.我只能说,技术不到家.Vision不够,这些想通过换工作可培养不来. 这篇文章其实我挺早就想写

【分享】VNR翻译日语游戏汉化简易图解教材

请[点击图片]到新链接看[原图].不然博客自动缩小图,看不清图解. 上面是用美少女万花镜来测试新版VNR翻译的如何,结果比我预料还要好.以前旧版根本比不上新版的.翻译非常准确.看了我上面的简易VNR图解,应该了解了怎样翻译了吧.接下来就是D.C.III.RX翻译. 来看下翻译效果吧. 最新版文本设置,其它还都是一样. D.C.III RX在VNR下全屏化 如果出现部分打开GAL游戏VNR却不自动弹出翻译窗口和翻译不出文本,请看下面解决方法. 提取文本后无法翻译或翻译不完整,不通顺解决方法 D.C