AcWing 95. 费解的开关(枚举首行操作、递推)

题目链接:点击这里
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
若该行位置为1,则对下一行的相应位置进行操作,使该行该位置由1变为0。

也就是,如果固定第一行的话,依次类推每次都对下一行进行相应的操作,那么,如果最后一行全为1则成功、有0则失败。

对第一行可以进行的操作有 2 5 2^5 种,因此,我们可以一一枚举每种操作,按照上面方法固定第一行进行递推,统计出所有成功操作中的最小值。

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
#include<map>
#include<set>

using namespace std;
typedef long long ll;
const int MOD = 10000007;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 1010;

char a[10][10];
int dx[5] = {0, 1, -1, 0, 0};
int dy[5] = {0, 0, 0, 1, -1};
int ans;


void turn(int x, int y)
{
	for(int i = 0; i < 5; ++i)
	{
		int newx = x + dx[i];
		int newy = y + dy[i];
		if(newx>=0&&newx<5&&newy>=0&&newy<5)
			a[newx][newy] ^= 1;
			//'0'(48)^1 = '1'(49) 
			//'1'(49)^1 = '0'(48) 
	}
}

int work()
{
	for(int k = 0; k < 1<<5; ++k)
	{
		int res = 0;
		char backup[10][10];
		memcpy(backup, a, sizeof a);
		
		for(int j = 0; j < 5; ++j)
		{
			//k的第j位如果是1,是指第一行的这一位应该被切换状态,而和其初始状态无关
			if(k >> j & 1)		//k的第j位为1 
			{
				res++;
				turn(0,j);
			}
		}
		
		for(int i = 0; i < 4; ++i)		//枚举前四行
		{
			for(int j = 0; j < 5; ++j)
			{
				if(a[i][j]=='0')	//上一行为1,对下一行的相应位置操作 
				{
					res++;
					turn(i+1, j);
				}
			}	
		}		
		
		bool flag = true;
		for(int j = 0; j < 5; ++j)
		{
			if(a[4][j]=='0')	//如果最后一行有0,则失败 
			{
				flag = false;
				break; 
			}
		} 
		
		if(flag)	ans = min(ans, res);
		memcpy(a, backup, sizeof backup);
	} 
	
	if(ans>6)	ans = -1;
	return ans;
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		for(int i = 0; i < 5; ++i)
			for(int j = 0; j < 5; ++j)
				cin>>a[i][j];
		
		ans = INF;
		cout<<work()<<endl;
	}
	return 0;
}
发布了727 篇原创文章 · 获赞 111 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/104241098