翻纸牌游戏
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3884 Accepted Submission(s): 1462
Problem Description
有一种纸牌游戏,很有意思,给你N张纸牌,一字排开,纸牌有正反两面,开始的纸牌可能是一种乱的状态(有些朝正,有些朝反),现在你需要整理这些纸牌。但是麻烦的是,每当你翻一张纸牌(由正翻到反,或者有反翻到正)时,他左右两张纸牌(最左边和最右边的纸牌,只会影响附近一张)也必须跟着翻动,现在给你一个乱的状态,问你能否把他们整理好,使得每张纸牌都正面朝上,如果可以,最少需要多少次操作。
Input
有多个case,每个case输入一行01符号串(长度不超过20),1表示反面朝上,0表示正面朝上。
Output
对于每组case,如果可以翻,输出最少需要翻动的次数,否则输出NO。
Sample Input
01
011
Sample Output
NO
1
解题之前需要明白这几个问题:
1.对于一组数据,最坏情况下翻多少次牌才能出来结果?
答:假设数据中有n张牌,那么最多的翻牌次数为n。因为一张牌只有两个面,所以一张牌只能翻一次,
翻两次以后和没有翻是一样的。
2.每一张牌最多翻多少次?所有的牌有多少种翻的方法?
答:每张牌最多翻一次,每张牌可以选择翻或者不翻,有两种状态。所有的牌如果都把这两种状态枚
举出来,肯定可以找到解。但是这么做需要枚举2的n次方,题目中的n最大是20,暴力枚举会超时。
3.使用解题思路中提供的方法,是否已经将所有情况都列举出来了?
答:没有。解题思路中的方法在使用的时候会发现,第一张牌不管在任何时候,都不会有任何的操作。
第一张牌的状态可能发生变化,但是第一张牌的另一个属性,翻与不翻从来没有发生过变化。
4.翻牌的顺序对结果是否有影响?
答:没有。翻牌的顺序不会影响结果的,因为翻每一张牌所产生的反应都是固定的,不会因为牌状态
不同而产生不同的结果。如果已经确定了翻那几张牌,那么不管翻牌的顺序是怎样的,某一张牌变化
次数是固定的,因此翻牌顺序不会影响牌
的结果。
综上所述:由于第一张牌的翻不翻这个属性始终没有变化,因此只需要枚举第一张牌翻不翻这个状态就可以,也就是枚举两次,就可以得到结果,然后再从这两个结果中找到一个较小的值输出就可以了。使用解题思路中描述的方法,每次进行完一轮操作以后,判断最后一张牌是否是正面,如果是,则说明找到一组解,否则继续找。
下面是代码:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s;
while(cin>>s)
{
bool a[50]={0};
int T=s.length();
int k=2;
int flag=0;
int sum=0,ans=9999999;
while(k--)//循环2次,用来枚举第一张牌的翻与不翻两种状态
{
sum=0;
for(int i=0;i<T;i++)//每次枚举的时候都要给a数组进行初始化
a[i]=s[i]=='1'?true:false;
if(k==0)//第一次循环不执行此步操作,第二次循环时候执行
{
a[0]=!a[0];//翻第一张牌
if(T>1)
a[1]=!a[1];
sum++;
}
for(int i=0;i<T-1;i++)//遍历T-1张牌
{
if(a[i]==true)//如果当前这张牌是背面,则需要翻其后面一张牌
{
sum++;
a[i]=!a[i];
a[i+1]=!a[i+1];
if(i+2<T)
a[i+2]=!a[i+2];
}
}
if(a[T-1]==false)//如果最后一张牌也是正面,说明这一组牌都已经是正面了
{
flag=1;
ans=ans>sum?sum:ans;
}
}
if(flag==0)
cout<<"NO"<<endl;
else
cout<<ans<<endl;
}
return 0;
}