-
总时间限制:
- 1000ms 内存限制:
- 1024kB
-
描述
-
有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。
然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。
当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。
输入
- 两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。 输出
- 至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。 样例输入
-
011 000
样例输出
-
1
啊,亏我做了这么多的贪心题了,这道题竟然想不出来,可恶啊……
于是去网上看了题解,然后又是一脸蒙蔽,又去找证明。。。
先说贪心:讨论两种情况,第1个按钮按不按,然后对于后面的按钮i,如果i不是目标状态,就按下i+1
思路有点像模拟啊
然后是证明:
对于每一个与目标状态不符的按钮,我们的选择是要么按它本身,要么按与它相邻的按钮,而连续两次改变这个按钮相当于没改变,因此不会存在同一个按钮按两次的情况
所以,考虑是否按第1个按钮,如果第一个按钮的状态确定了,那么后一个按钮按与不按也就确定了,可以类推下去。然后根据前面不会存在同一个按钮按两次的情况,当然是不能往回按的
我曾疑惑这里为什么要讨论是否要按第1个按钮的情况,但是需要讨论的,给出一个理由,按第1个按钮,会使第1,2两个按钮都发生变化,如果第1个按钮是不匹配的,你按了
自然没有问题,而第2个按钮你就不能按了,而如果第1个按钮时匹配的,你按了,就意味着你必须要按第2个按钮,而着又会导致第3个按钮改变,所以要分情况讨论
好了,姑且就这样吧,我是再不能了
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
const int MAXN=35;
const int inf=0x3f3f3f3f;
using namespace std;
char s1[MAXN],s2[MAXN],temp[MAXN];
int len;
inline void change(int i){
temp[i]=temp[i]=='0'?'1':'0';
}
int solve1(){//!第一个按钮不按
int ans=0; strcpy(temp,s1);
for(int i=1;i<len;i++)
if(temp[i-1]!=s2[i-1])
change(i-1),change(i),change(i+1),ans++;
for(int i=0;i<len;i++)
if(temp[i]!=s2[i]) return inf;
return ans;
}
int solve2(){//!第一个按钮按
int ans=0; strcpy(temp,s1);
change(0); change(1); ans++;
for(int i=1;i<len;i++)
if(temp[i-1]!=s2[i-1])
change(i-1),change(i),change(i+1),ans++;
for(int i=0;i<len;i++)
if(temp[i]!=s2[i]) return inf;
return ans;
}
int main()
{
scanf("%s%s",s1,s2); len=strlen(s1);
int ans=min(solve1(),solve2());
if(ans==inf) printf("impossible");
else printf("%d",ans);
}