Trim the Nails (DFS+状态压缩)
几星期前一次组队赛的题了,今天下午就找了这道题来补了,顺便学习了下状态压缩和位运算的一些知识了。。
思路:看题就知道是DFS了,但是状态的表示需要压缩。
具体,初始状态0000011111(M个1),目标状态0000000(全零)
指甲刀也可以用一个压缩的整数met来表示,0表示good,1表示bad。这样剪一次指甲后的状态就是status&met。
其他的还有些细节要注意:
1. 答案为-1的情况,指甲刀全为bad;
2. 指甲刀可以正反使用;
3. 两个简化措施:将met两端的bad去掉,每次剪完将status最末端的0去掉;
4. 只有一个为good的情况可以直接输出答案,优化时间。
代码到是挺简洁的,不过写起来还是蛮麻烦的,可能与刚接触状态压缩有关吧~
#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#define OP(s) cout<<#s<<"="<<s<<" ";
#define PP(s) cout<<#s<<"="<<s<<endl;
using namespace std;
int met1,met2,ans;
void DFS(int dep,int status)
{
if (status == 0)
{
if (dep < ans) ans = dep;
return;
}
while (!(status&1)) status = status>>1;//!wrong status^1 这里是要取最后一位的值,并判断其0or1
DFS(dep+1,status&met1);
DFS(dep+1,status&met2);
}
int main()
{
freopen("test.txt","r",stdin);
int N,M;
while (~scanf("%d",&N))
{
char str[100];
scanf("%s",&str[1]);
met1 = met2 = ~0;
int num = 0;
for (int i = 1;i <= N;i++)
if (str[i] == '*')
{
num++;
met1 = met1&~(1<<i-1);
met2 = met2&~(1<<N-i);
}
if (num) while (met1&1) met1 = met1>>1;
if (num) while (met2&1) met2 = met2>>1;
scanf("%d",&M);
if (!num)
{
printf("-1\n");
continue;
}
if (num == 1)
{
printf("%d\n",M);
continue;
}
ans = 1<<30;
int S = ~(~0<<M);
DFS(0,S);
printf("%d\n",ans);
}
return 0;
}
/*
先去补充了下位运算和状态压缩的一些知识,然后再去写了。
主要有两个错误:
1.首先是查看压缩状态的方法不对
正确的是这样子,for (int i = 15;i >= 1;i--) if (status>>i-1 & 1) cout<<1;else cout<<0;cout<<endl;
2.判断第X位是什么写错了
while (!(status&1)) status = status>>1;
*/