黑白棋问题——位运算及广度优先

本文介绍了一种使用位运算和广度优先搜索解决类黑白棋问题的方法。给定一个由0和1组成的字符串,每次可以改变一个数字,同时影响左右两侧的数字。目标是找到使字符串变为全0的最小操作次数。对于长度小于20的字符串,通过将字符串转换为数字并使用队列进行广度优先搜索,判断是否可以达到全0状态。在搜索过程中,利用异或运算更新数字,并避免重复状态,直至队列为空或找到解决方案。示例给出了不同输入下的操作次数或“NO”输出,表明某些情况无法达到全0状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

There is a string which consists 0s and 1s only.
Each time you can change one digit, with 0 changed to 1, or 1 changed to 0.
But when you change the digit, the digits on its left and right is changing in the same way.
Please tell me the minimum moves to change the string to 00…000.
If it is impossible please output “NO” in a single line.

输入

In each line there is a string. The length of the string is shorter than 20.

输出

For each string you have to output the minimum number or “NO” in a single line.

样例输入

01
011
101

样例输出

NO
1
2

应该是真正意义上的第一次用位运算来模拟,摸着石头过河的感觉。

题意类黑白棋问题,给一个由01组成的字符串,每次可以改变一个数字(同时两边的数字也会改变),问多少次操作后会得到全0序列。

这道题最大长度为20,也就是说所有情况都可以用1024*1024一下的数字来表示, 而一百万个int 的空间消耗也是可以接受的。

 

流程:

首先将输入字符串转化为数字,入队。

队头出队,如果满足条件,则输出当前操作数。否则将这个数进行位运算。 改变的三位可以用与7(111)异或来得到。因1^1=0,0^1=1. 其他位与0异或,任何数与0异或还是他本身。 例如当前数字二进制表示为101101,当想翻转前三个数字时,得到的数为101101^111000=010101 。这里要注意的是,要单独考虑翻转前两个数与最后两个数的情况,此时应该与3异或。

得到新数后,在flag数组中校验,如果这个数之前未出现过,则入队。

因为之前出现过的情况都不会再入队,故不会有循环出现。当队列为空时,说明翻转不可能完成。

 

代码:

#include<iostream>
#include<queue>
#include<string>
#include<algorithm>
using namespace std;
bool flag[2000000];
class node
{
public:
	int ct;
	int num;
};
queue<node >Q;
int main()
{
	string s;
	int i,j;
	while(cin>>s)
	{
		while(!Q.empty())
			Q.pop();
		memset(flag,0,sizeof(flag));
		int len=s.length();
		int sum=0;
		int temp=1;
		for(i=len-1;i>=0;i--)
		{
			sum+=temp*(s[i]-'0');
			temp=temp<<1;
		}
		if(sum==0)
		{
			cout<<0<<endl;
			continue;
		}
		if(sum==1&&len==1)
		{
			cout<<1<<endl;
			continue;
		}
		if(len==2)
		{
			if(sum==2||sum==1)
			{
				cout<<"NO"<<endl;
				continue;
			}
			if(sum==3)
			{
				cout<<1<<endl;
			    continue;
			}
		}


		node p,q;
		p.ct=0;
		p.num=sum;
		flag[sum]=1;
		int suc=0;
		Q.push(p);
		while(!Q.empty())
		{
			p=Q.front();
		//	cout<<p.num<<endl;
			Q.pop();
			if(!p.num)
			{
				suc=p.ct;
				break;
			}
			sum=p.num^(3<<(len-2));
			if(!flag[sum])
			{
				flag[sum]=1;
				q.num=sum;
				q.ct=p.ct+1;
				Q.push(q);
			}
			for(i=0;i<=len-3;i++)
			{
				sum=p.num^(7<<i);
				if(!flag[sum])
				{
					flag[sum]=1;
					q.num=sum;
					q.ct=p.ct+1;
					Q.push(q);
				}
			}
			sum=p.num^3;
			if(!flag[sum])
			{
				flag[sum]=1;
				q.num=sum;
				q.ct=p.ct+1;
				Q.push(q);
			}
		}
		if(suc==0)
			cout<<"NO"<<endl;
		else
			cout<<suc<<endl;

	}
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值