本文主要是介绍E - Red Polyomino 关于回溯 和爆搜,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这题就是爆搜。。虽然看似有2^(nn)的复杂度。。
但是实际上因为相连的限制。。种类非常有限。。样例88的就可以看出来。
所以就是爆搜而已。。
记录这题是因为。之前一直在思考回溯 到底和爆搜什么关系。。
目前算是阶段性的一个理解。。
回溯只不过是爆搜的一种方式而已。。
如果我们可以每层递归 都是拷贝。而不是引用。。实际上是不需要回溯的。
回溯只在于样本只有一份。就是传引用的时候。我们只有通过恢复现场。。来尝试其他的可能。
下面两个版本的写法。。就证明了这点。。
总结:回溯只不过是恢复现场的一种手法。。如果现场不需要恢复(每层都拷贝一份新的) 就不需要回溯🔥
而爆搜是一种枚举所有可能的手法。。分步X分类。比较经典的爆搜模型 就是完全二叉树 每个节点两种可能 选和不选。
题目链接
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll __int128_t
#define ar array<int, 2>
#define arr array<int, 3>
int n, m, k, inf = 1LL << 61, mod = 998244353;// 1e9+7;
const int N = 5e5 + 50;
int ans;
void dfs(vector<string>s) {int cnt = 0;for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j) {cnt += s[i][j] == 'o';}if (cnt == k) {ans++;return ;}for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j) {if (s[i][j] != '.')continue;if (cnt) {int d[5] {1, 0, -1, 0, 1};bool ok = 0;for (int c = 0; c < 4; ++c) {int x = i + d[c], y = j + d[c + 1];if (x >= 0 && y >= 0 && x < n && y < n && s[x][y] == 'o')ok = 1;}if (ok == 0)//就是旁边一定要有红色的。。因为相连continue;}s[i][j] = 'o';dfs(s);s[i][j] = '#';dfs(s);//我们传的是整个拷贝的s。这边就不需要回溯。return ;}
}
void solve() {cin >> n >> k;vector<string>a(n);for (auto&a : a)cin >> a;dfs(a);cout << ans;
};signed main() {ios::sync_with_stdio(false);cin.tie(0);cout << fixed << setprecision(15);
#ifdef DEBUGfreopen("../1.in", "r", stdin);
#endif//init_f();//init();//expr();// int T; cin >> T; while(T--)solve();return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll __int128_t
#define ar array<int, 2>
#define arr array<int, 3>
int n, m, k, inf = 1LL << 61, mod = 998244353;// 1e9+7;
const int N = 5e5 + 50;
int ans;
void dfs(vector<string>&s) {int cnt = 0;for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j) {cnt += s[i][j] == 'o';}if (cnt == k) {ans++;return ;}for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j) {if (s[i][j] != '.')continue;if (cnt) {int d[5] {1, 0, -1, 0, 1};bool ok = 0;for (int c = 0; c < 4; ++c) {int x = i + d[c], y = j + d[c + 1];if (x >= 0 && y >= 0 && x < n && y < n && s[x][y] == 'o')ok = 1;}if (ok == 0)//就是旁边一定要有红色的。。因为相连continue;}s[i][j] = 'o';dfs(s);s[i][j] = '#';dfs(s);s[i][j] = '.';//回溯本质上就多了这一步而已。。但是可以传引用。。!!!!return ;}
}
void solve() {cin >> n >> k;vector<string>a(n);for (auto&a : a)cin >> a;dfs(a);cout << ans;
};// 回溯只不过是为了还原现场而已。。如果传的不是引用。。。每个图都拷贝一份。那么根本不需要回溯!!!
//回溯只不过是爆搜的一种实现策略。。而已。。每个图都拷贝一份。那么根本不需要回溯!
// signed main() {ios::sync_with_stdio(false);cin.tie(0);cout << fixed << setprecision(15);
#ifdef DEBUGfreopen("../1.in", "r", stdin);
#endif//init_f();//init();//expr();// int T; cin >> T; while(T--)solve();return 0;
}
这篇关于E - Red Polyomino 关于回溯 和爆搜的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!