NOI2017 游戏 洛谷 P3825

本文深入探讨了2-SAT算法在解决特定问题中的应用,通过实例详细讲解了如何利用2-SAT算法进行建图与求解。文章首先介绍了问题背景,随后展示了算法的具体实现过程,包括预处理、Tarjan算法的应用以及最终解决方案的设计。此外,还分享了在实际编码过程中可能遇到的陷阱及应对策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.luogu.com.cn/problem/P3825

(NOI也不过如此,盲目自信.jpg

这题我们知道对于地图a,b,c来说,只有两种选择,那么就是2-sat裸题了,

考虑地图x,由于d<=8,我们让它要么是A,B要么是B,C,就包含所有情况了,只需要2^d的枚举

之前建图忘记对称建了,WA了一发,身败名裂.jpg

对称建也就是对于i要选择j,这个命题等于 选择 opp(j) 要选择 opp(i) 

#include<bits/stdc++.h>
using namespace std;

const int maxl=1e5+10;

int n,d,m,ind,top,ff;
int dfn[maxl],low[maxl],f[maxl],s[maxl];
int a[maxl][2],h[maxl][5];
char ch[maxl],tmp[3],out[maxl];
bool ansflag;
bool in[maxl],ans[maxl];
vector <int> xx,e[maxl];

inline void prework()
{
	scanf("%d%d",&n,&d);
	scanf("%s",ch+1);
	for(int i=1;i<=n;i++)
	{
		if(ch[i]=='x')
			xx.push_back(i);
		if(ch[i]=='a')
			a[i][0]=2,a[i][1]=3;
		if(ch[i]=='b')
			a[i][0]=1,a[i][1]=3;
		if(ch[i]=='c')
			a[i][0]=1,a[i][1]=2;
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&h[i][1]);
		scanf("%s",ch);h[i][2]=ch[0]-'A'+1;
		scanf("%d",&h[i][3]);
		scanf("%s",ch);h[i][4]=ch[0]-'A'+1;
	}
}

inline void tarjan(int u)
{
	dfn[u]=low[u]=++ind;
	in[u]=true;s[++top]=u;
	for(auto v : e[u])
	if(!dfn[v])
	{
		tarjan(v);
		low[u]=min(low[u],low[v]);
	}else if(in[v])
		low[u]=min(low[u],dfn[v]);
	if(dfn[u]==low[u])
	{
		ff++;int v;
		do
		{
			v=s[top--];
			f[v]=ff;in[v]=false;
		}while(u!=v);
	}
}

inline bool solv()
{
	ff=0;ind=0;top=0;
	for(int i=1;i<=2*n;i++)
	{
		dfn[i]=low[i]=f[i]=0;
		e[i].clear();in[i]=true;
	}
	int u,v;
	for(int i=1;i<=m;i++)
	{
		u=h[i][1];v=h[i][3];
		for(int j=0;j<=1;j++)
		if(h[i][2]==a[u][j])
		{
			if(h[i][4]!=a[v][0] && h[i][4]!=a[v][1])
				e[u+j*n].push_back(u+(1-j)*n);
			else if(h[i][4]==a[v][0])
			{
				e[u+j*n].push_back(v);
				e[v+n].push_back(u+(1-j)*n);
			}
			else 
			{
				e[u+j*n].push_back(v+n);
				e[v].push_back(u+(1-j)*n);
			}
		}
	}
	for(int i=1;i<=2*n;i++)
	if(!dfn[i])
		tarjan(i);
	for(int i=1;i<=n;i++)
	if(f[i]==f[i+n])
		return false;
	for(int i=1;i<=n;i++)
		ans[i]=f[i]>f[i+n];
	return true;
}

inline void dfs(int k)
{
	if(k==d)
	{
		if(solv())
		{
			ansflag=true;
			for(int i=1;i<=n;i++)
				out[i]=a[i][ans[i]]+'A'-1;
		}
		return;
	}
	a[xx[k]][0]=1;a[xx[k]][1]=2;
	dfs(k+1);
	if(ansflag) 
		return;
	a[xx[k]][0]=2;a[xx[k]][1]=3;
	dfs(k+1);
}

inline void mainwork()
{
	ansflag=false;
	dfs(0);
}

inline void print()
{
	if(!ansflag)
		printf("-1");
	else
		for(int i=1;i<=n;i++)
			printf("%c",out[i]);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值