第一次写时恢复现场的地方使用backup备份会出现问题,一直没有发现,再一位大佬(大佬的代码)的指点下终于知道了问题所在,看了他的代码知道恢复现场时可以再翻回来。
题中如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。
只要DFS时先改变把手的状态就可以了。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
const int N = 5;
char g[N][N];
vector<PII> ans, tmp;
void turn_one(int x, int y)
{
if (g[x][y] == '+') g[x][y] = '-';
else g[x][y] = '+';
}
void turn_all(int x, int y)
{
for (int i = 0; i < 4; i++)
{
turn_one(x, i);
turn_one(i, y);
}
turn_one(x, y);
}
void dfs(int x, int y)
{
// 如果说所有的把手都操作完了就看看冰箱能否打开
if (x == 3 && y == 4)
{
bool success = true;
for (int i = 0; i < 4; i++)
for (int j = 0; j <4; j++)
if (g[i][j] == '+')
{
success = false;
goto end;
}
end:
if (success)
if (ans.empty() || tmp.size() < ans.size())
ans = tmp;
return;
}
// 判断边界,如果y出界了就往下一行移动
if (y == 4) x++, y = 0;
// 操作把手(x, y)
turn_all(x, y);
tmp.push_back({ x, y });
dfs(x, y + 1);
// 恢复现场
tmp.pop_back();
turn_all(x, y);
// 不操作把手(x, y)
dfs(x, y + 1);
}
int main()
{
for (int i = 0; i < 4; i++) scanf("%s", g[i]);
// 从(0, 0)开始DFS
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);
return 0;
}
在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。
太死板也不好,goto适用于跳出多重循环和debug,OS中也有很多goto
飞行员兄弟,不开飞机,改开冰箱门了
建议改为
这里success=false;无效,直接这样写就行了
8000+ms 啊 ,有没有更好的办法
https://www.acwing.com/solution/content/44927/
数学方法好像只要几十ms
兄弟们注意以下,用backup来还原的话,千万不要开成全局变量,要开在dfs内部,我调了好半天才发现问题
求问,为什么DFS的方法这么快?我用普通枚举的方法跑完所有测试数据大概需要5000多ms,用DFS的方法只需要1000多ms。
大佬,想问一下结束条件为什么是x==3&&y==4
因为g从(0,0)开始,最后一个开关应该是(3,3)操作完它y再加1之后进行dfs,dfs接收到的是(3,4)。即dfs接收到(3,4)时已经把所用开关都操作完了。
谢谢,大佬
大佬{x ,y} 这种写法是 make_pair(x, y) 的简化写法吗,从什么版本开始的编译器支持这种写法?
简化版turn_all
👍
非常感谢!
能过吗?
不用备份也能过欸
你知道backup出了什么问题吗,我刚开始也是这做,发现过不了,用turn翻回来就能过了,这是为什么
可以啊我试了下没问题啊看看你的代码
为什么这里恢复现场之后还要有不操作把手再dfs一个呢?之前做的全排列那种都是恢复现场就好了,不用再dfs一次,求解答~
全排列是每一个数都要选的 所以就不用dfs不选的情况
哥哥们,我想问下为什么不能先不操作后操作呢,直觉上这样好像可以的,虽然vector一直加元素,但有没有办法做到这样呢~
可以把不操作把手那步放在操作把手的前面的
但是vector里面不是只会增加元素吗,删除vector里的元素这个操作应该放在哪呢
不操作把手就不用往vector加元素 删除的话是pop_back()
什么时候删除呢
因为不操作就不用加 所以不用删除
这样是错的~
不对,wa掉了TAT
你翻转的操作加了吗
没有,这样的确过了,但是为什么还要恢复现场呢
这里恢复现场是因为操作过把手了丫
啊这,看来我还是没深入理解$dfs$,总之,谢谢您为我解惑TAT
加油丫嘻嘻TvT
我本来也想写一遍dfs来做,但是递归那一部分总是写不好,你的写的很好,学习了!
牛!!!!
dfs可以理解,关键是题的哪些特性想到使用dfs的呢
dfs就是暴力枚举,枚举每一步的情况
妙~啊~