Description
给你N张纸牌,一字排开,纸牌有正反面,正面写有0,反面写有1。开始的纸牌可能是一种乱的状态(有0有1)现在你需要整理这些纸牌。但麻烦的是,每当你翻一张纸牌时,他左右两张纸牌也必须跟着翻动,现在给你一个乱的状态,问你能否把他们整理好,使得每张纸牌都正面朝上,如果可以,最少需要多少次操作。
Input
有多组数据,每组数据输入一行01符号串(长度20以内),0表示正面朝上,1表示反面朝上。
Output
对于每组数据,如果可以翻称全都是正面,输出最少需要翻动的次数,否则输出NO。
Sample Input
01 011
Sample Output
NO 1
解题思路:用bfs进行一个一个的搜索,因为串中只有01,所以可以将串转换成十进制,这样就可以产生2^20个不同的数,然后标记数组开2^20这么大即可!
搜索每一个纸牌,当0换1,当1换0,直到都为0结束。这里换的时候需要用与运算,我开始直接换后一直超时。。。换的时候直接对十进制数进行加或减去相应位置的值即可
代码:
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
#include <string.h>
using namespace std;
struct node{
int lens;
int steps;
};
int flag,cot;
queue<node>q;
int visit[1100000];
int table[] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576};
int transition(string s)
{
int figure = 0,point = 0;
for(int i=s.length()-1;i>=0;i--)
{
figure += (s[i] - '0')* table[point++];
}
return figure;
}
void fun(struct node * temp,int i)//进行交换
{
int k = table[i];
if((temp->lens & k) == 0)//当与为0即为要换成1,所以加
{
temp->lens += k;
}
else//否则为1即为要换成0,所以减
{
temp->lens -= k;
}
}
void bfs(string s)
{
while(!q.empty())q.pop();
int i;
node s_temp;
s_temp.steps = 0;
s_temp.lens = transition(s);
visit[s_temp.lens] = 1;
q.push(s_temp);
int len = s.length();
while(!q.empty())
{
node oper = q.front();
s_temp = oper;
flag = 0;
for(i=0;i<len;i++)
{
s_temp = oper;
fun(&s_temp,i);
if(i - 1 >= 0)
{
fun(&s_temp,i-1);
}
if(i + 1 < len)
{
fun(&s_temp,i+1);
}
s_temp.steps = oper.steps + 1;
int trans = s_temp.lens;
if(visit[trans] == 0)
{
if(trans == 0)//满足跳出
{
flag = 1;
break;
}
q.push(s_temp);
visit[trans] = 1;
}
}
if(flag)
{
cot = s_temp.steps;
break;
}
q.pop();
}
}
int main()
{
string s;
while(cin >> s)
{
memset(visit,0,sizeof(visit));
flag = 0;
cot = 0;
if(transition(s) == 0)
{
cout << "0" <<endl;
continue;
}
bfs(s);
if(flag)
{
cout << cot << endl;
}
else
{
cout << "NO" << endl;
}
}
return 0;
}