活动地址:https://www.acwing.com/activity/content/19/
“飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有 16 个把手的冰箱。
已知每个把手可以处于以下两种状态之一:打开或关闭。
只有当所有把手都打开时,冰箱才会打开。
把手可以表示为一个 4×4 的矩阵,您可以改变任何一个位置 [i,j] 上把手的状态。
但是,这也会使得第 i 行和第 j 列上的所有把手的状态也随着改变。
请你求出打开冰箱所需的切换把手的次数最小值是多少。
输入格式
输入一共包含四行,每行包含四个把手的初始状态。
符号 + 表示把手处于闭合状态,而符号 - 表示把手处于打开状态。
至少一个手柄的初始状态是关闭的。
输出格式
第一行输出一个整数 N,表示所需的最小切换把手次数。
接下来 N 行描述切换顺序,每行输出两个整数,代表被切换状态的把手的行号和列号,数字之间用空格隔开。
注意:如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。
数据范围
1≤i,j≤4
输入样例:
-+--
----
----
-+--
输出样例:
6
1 1
1 3
1 4
4 1
4 3
4 4
题目地址:https://www.acwing.com/problem/content/118/
如图若操作,红色框的把手,则蓝色框内的所有把手都会变化一次且仅一次(红色框也是变一次)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
char a[4][4]; //记录把手状态
typedef pair<int, int> PII;
vector<PII> ans, temp; //记录操作的把手位置
void turn(int x, int y)
{
for (int i = 0; i < 4; i ++)
{
a[x][i] ^= 1; //改变该行
a[i][y] ^= 1; //改变该列
}
a[x][y] ^= 1;
}
void dfs(int x, int y)
{
//如果所有把手都试了
if(x == 3 && y == 4)
{
//下面查看所有把手是否都打开了
for (int i = 0; i < 4; i ++ )
for (int j = 0; j < 4; j ++ )
{
if(a[i][j] == 0) //如果有把手关闭,则不成功
{
return;
}
}
if (ans.empty() || temp.size() < ans.size()) //如果答案步骤为空,
ans = temp; //或者有更小的操作步骤则更新答案
return;
}
//判断是否需要换行
if(y == 4)
{
x ++;
y = 0;
}
char backup[4][4]; //备份把手
memcpy(backup, a, sizeof a); //备份把手情况
//操作把手,记录把手位置,枚举下一个把手
turn(x, y);
temp.push_back({x,y});
dfs(x, y + 1);
//不操作该处把手,先清除该把手位置,再还原把手情况
temp.pop_back();
memcpy(a, backup, sizeof a);
dfs(x, y + 1);
}
int main()
{
char ch;
for (int i = 0; i < 4; i ++)
{
for (int j = 0; j < 4; j ++)
{
ch = getchar();
if (ch == '-') //把手打开为 1 关闭为 0
a[i][j]=1;
}
getchar();
}
dfs(0,0);
cout << ans.size() <<endl;
for (int i = 0; i < ans.size(); i ++ )
printf("%d %d\n",ans[i].first + 1, ans[i].second + 1); //答案的数据是从 1 开始的需要加一
return 0;
}
题目链接:116. 飞行员兄弟
相关题目:95. 费解的开关