#270 关灯 [DP]
题解
倒着DP。这是道没有枚举上限的DP,所以倒着来应该是最好的。
分析可得,倒数第 个时刻,按下某一个灯最多能够影响到 个灯。所以就可以以这个信息为关键转移。
设 表示倒数第 个时刻,所有灯的开关状况为 的方案是否可行。
具体转移看代码。
注意这里实际上并没有得到具体是哪个灯被操作了,只是从之前的状态得到后面可能出现的合法状态(有点像宽搜)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int f[50][(1<<20)+5];
int main(){
char s[25];scanf("%s",s);
int len=strlen(s),Start=0;
int Limit=(1<<len)-1;
for(int i=0;i<len;i++)
Start|=((1-s[i]+'0')<<i);
//由于下面的转移中,被操作的一整段灯是往左移的(这样好写代码)
//所以这里必须把输入倒着来
f[1][Start]=true;
for(int i=1;;i++){
if(f[i][Limit]){printf("%d",i-1);return 0;}
for(int j=0;j<=Limit;j++){
if(!f[i][j])continue;
f[i+1][j]=true;
for(int k=(1<<i)-1;k;k<<=1,k&=Limit)
f[i+1][j^k]=true;
}
}
}