交换游戏 (记忆化搜索 状压)

链接:https://ac.nowcoder.com/acm/contest/4462/C
来源:牛客网
 

交换游戏

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

一列上有12个孔,这12个孔中有些孔被遮挡住了。

假定我们用 '-' 来表示没被遮挡住的孔,用 'o' 来表示被遮挡住的孔。

如果相邻的三个孔有两个孔被遮挡,并且被遮挡的两个孔相邻,就是 '-oo' 和 'oo-'。

对于这样的三个孔,我们可以将中间的孔的遮挡物移开,代价是将一端的遮挡物移到另一端没有被遮挡的孔上面。

对于一列给定的孔,你的任务是制定操作的顺序,使得最后剩余的被遮挡的孔的个数最少,并输出最后剩余的被遮挡的孔的个数。

输入描述:

 

第一行输入一个n,n≤105n, n \le 10^5n,n≤105。

接下来n行,每行12个字符,代表孔的状态。

输出描述:

对于每行输入在一行中输出一个数字代表答案。

示例1

输入

复制5 ---oo------- -o--o-oo---- -o----ooo--- oooooooooooo oooooooooo-o

5
---oo-------
-o--o-oo----
-o----ooo---
oooooooooooo
oooooooooo-o

输出

复制1 2 3 12 1

1
2
3
12
1

一共12个孔,只有2^12=4096种情况,但是查询次数很多,我们可以考虑用二进制1和0表示‘o’和‘-’两种状态,进行状态压缩,用一个二进制数代表一种情况。然后再在记忆化搜索的过程中把已知情况的答案记录下来,方便下次直接用。

搜索的时候就找 '-oo' 和 'oo-',注意到它们有共同点:中间是1,两边不相同。“将中间的孔的遮挡物移开,将一端的遮挡物移到另一端没有被遮挡的孔上面。”其实就是把中间的1变为0,再把两边互换,对于二进制数011和110,我们只要将它^111即异或7(1和0异或上0不变,异或1则可互换)

来自官方题解

附加:运算符优先级

#include<bits/stdc++.h>
using namespace std;
int f[1<<12];
int n;
char s[20];
int dfs(int x)
{
	if(f[x]||x==0) return f[x];
	int ans=0;
	for(int i=0;i<12;i++)
	{
		if(x>>i&1) ans++;
	}
	for(int i=0;i<10;i++)
	{
		if( x>>i+1&1 && x>>i&1 ^ x>>i+2&1) ans=min(ans,dfs(x^(7<<i)));
		//主要运算优先级 +》<< 》& 》 ^ 》 && 
	}
	f[x]=ans;
	return ans;
}	
int main()
{
	scanf("%d",&n);
	while(n--)
	{
		scanf("%s",s);
		int x=0;
		for(int i=0;i<12;i++)
		{
			x=(x<<1)+(s[i]=='o'? 1:0);
		}
		printf("%d\n",dfs(x));
	}
}
发布了54 篇原创文章 · 获赞 7 · 访问量 3432

猜你喜欢

转载自blog.csdn.net/qq_43868883/article/details/104877893
今日推荐