链接: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
扫描二维码关注公众号,回复: 10027174 查看本文章输入
复制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)); } }