kuangbin专题二:搜索进阶
前:这节以后,我尽可能的增加代码的可读性,为此将牺牲一定程度的简洁。
思路:cantor展开。
#include <iostream> #include <cstring> #include <string> #include <queue> #include <vector> #include <algorithm> using namespace std; const int maxn = 372880; int factor[10]; int ary[10]; bool vis[maxn]; string Path[maxn]; char op[] = {'u', 'd', 'l', 'r'}; int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1}; int cantor(int *ary, int n){ int res = 0; for(int i = 0; i < n; i++){ int small = 0; for(int j = i + 1; j < n; j++) if(ary[j] < ary[i]) small++; res += small * factor[n - 1 - i]; } return res; } void decantor(int *ary, int n, int k){ vector<int> vec; for(int i = 0; i < 9; i++) vec.push_back(i); for(int i = 0; i < 9; i++){ int t = k / factor[n - 1 - i]; k %= factor[n - 1 - i]; ary[i] = vec[t]; vec.erase(vec.begin() + t); } } void bfs(){ for(int i = 0; i < 9; i++) ary[i] = (i + 1) % 9; queue<int> q; int st = cantor(ary, 9); q.push(st); vis[st] = true; Path[st] = ""; while(q.size()){ int p = q.front(); q.pop(); decantor(ary, 9, p); int zero = find(ary, ary + 9, 0) - ary; int x = zero / 3, y = zero % 3; for(int i = 0; i < 4; i++){ int nx = x + dx[i], ny = y + dy[i]; if(nx>=0 && nx<3 && ny>=0 && ny<3){ int newzero = nx * 3 + ny; swap(ary[zero], ary[newzero]); int nxt = cantor(ary, 9); if(!vis[nxt]){ vis[nxt] = true; Path[nxt] = op[i] + Path[p]; q.push(nxt); } swap(ary[zero], ary[newzero]); } } } } void init(){ factor[0] = 1; for(int i = 1; i <= 9; i++) factor[i] = factor[i-1] * i; } int main(){ init(); bfs(); char c; while(cin >> c){ ary[0] = c == 'x' ? 0 : c - '0'; for(int i = 1; i < 9; i++){ cin >> c; ary[i] = c == 'x' ? 0 : c - '0'; } int value = cantor(ary, 9); if(!vis[value]) cout << "unsolvable" << endl; else cout << Path[value] << endl; } return 0; }
思路: 双向bfs,但是一直WA。。。先挖坑以后再填。
思路:简单回溯法,注意输出格式。
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int maxn = 372880; int edge[22][3]; bool vis[22]; int Path[22]; int resn; void Print(){ cout << ++resn << ": "; for(int i = 1; i <= 20; i++) cout << Path[i] << ' '; cout << Path[21] << endl; } void dfs(int dep, int city, int st){ if(dep == 20) { for(int i = 0; i < 3; i++){ int v = edge[city][i]; if(v == st){ Path[dep] = city; Path[dep+1] = st; Print(); } } return; } vis[city] = true; Path[dep] = city; for(int i = 0; i < 3; i++){ int v = edge[city][i]; if(!vis[v]){ dfs(dep+1, v, st); } } vis[city] = false; } int main(){ for(int i = 1; i <= 20; i++) for(int j = 0; j < 3; j++) cin >> edge[i][j]; int m; while(cin >> m && m){ resn = 0; dfs(1, m, m); } return 0; }
思路:巨坑的题目,坑如下:
- 碉堡不能经过,这点题目里没说。
- 人可以穿过子弹,只要人和子弹不在同一时间同一地点。
- 敌军碉堡可以建立在我方基地(???)。
#include<iostream> #include<queue> #include<cstring> #include<vector> using namespace std; const int maxn = 105; int n, m, k, d; int mm[maxn][maxn]; bool vis[maxn][maxn][1005]; int dx[] = {1, -1, 0, 0, 0}, dy[] = {0, 0, 1, -1, 0}; char invdir[] = {'N', 'S', 'W', 'E'}; struct Castle{ char dir; int t, v; } castle[maxn]; void init(){ memset(mm, 0, sizeof(mm)); memset(vis, false, sizeof(vis)); } void read_castle(int casNum){ for(int i = 1; i <= casNum; i++){ int x, y; cin >> castle[i].dir >> castle[i].t >> castle[i].v; cin >> x >> y; mm[x][y] = i; } } inline bool in_map(int x, int y){ return x>=0 && x<=m && y>=0 && y<=n; } bool can_hit(Castle &ca, int nx, int ny, int x, int y, int tt, int dirN){ if(ca.dir != invdir[dirN]) return false; int diff = abs(nx - x) + abs(ny - y); if((diff % ca.v == 0) && (diff <= tt * ca.v) && ((tt - diff / ca.v) % ca.t == 0)) return true; return false; } bool is_safe(int x, int y, int tt){ if(!in_map(x, y) || mm[x][y]) return false; for(int i = 0; i < 4; i++){ int nx = x, ny = y; while(in_map(nx, ny) && !mm[nx][ny]) nx += dx[i], ny += dy[i]; if(in_map(nx, ny)){ Castle &ca = castle[mm[nx][ny]]; if(can_hit(ca, nx, ny, x, y, tt, i)) return false; } } return true; } struct Pos{ int x, y, t; }; int bfs(){ queue<Pos> q; Pos st{0, 0, 0}; q.push(st); vis[0][0][0] = true; while(q.size()){ Pos p = q.front(); q.pop(); if(p.t > d) return 0; if(p.x == m && p.y == n) return p.t; for(int i = 0; i < 5; i++){ int nx = p.x + dx[i], ny = p.y + dy[i]; int nt = p.t + 1; if(!vis[nx][ny][nt] && is_safe(nx, ny, nt)){ Pos tmp{nx, ny, nt}; q.push(tmp); vis[nx][ny][nt] = true; } } } return 0; } int main(){ while(cin >> m >> n >> k >> d){ init(); read_castle(k); int res = bfs(); if(res == 0) cout << "Bad luck!" << endl; else cout << res << endl; } }
思路:题目数据比较水,用A*可过(疯狂TLE)。看到题目第一反应是DP,但没想到比较简单的做法。
#include<iostream> #include<cstring> using namespace std; const int maxn = 10; int n; int pos[maxn], left_len; string element = "ACGT"; string DNA[maxn]; int estimate(){ int res = 0; for(int i = 0; i < n; i++) res = max(res, (int)(DNA[i].length() - pos[i])); return res; } bool found; int max_dep; void dfs(int dep){ if(dep + estimate() > max_dep) return; else if(left_len == 0){ found = true; return; } int tmp[maxn], orign_len = left_len; for(int i = 0; i < n; i++) tmp[i] = pos[i]; for(int i = 0; i < 4; i++){ bool match = false; for(int j = 0; j < n; j++){ if(pos[j] < DNA[j].length() && DNA[j][pos[j]] == element[i]){ match = true; pos[j]++; left_len--; } } if(match){ dfs(dep+1); if(found) return; // cancel above changes for(int j = 0; j < n; j++){ pos[j] = tmp[j]; } left_len = orign_len; } } } void read_data(){ cin >> n; left_len = 0; max_dep = 0; found = false; memset(pos, 0, sizeof(pos)); for(int i = 0; i < n; i++){ cin >> DNA[i]; left_len += DNA[i].length(); max_dep = max(max_dep,(int)DNA[i].length()); } } int main(){ int t; cin >> t; while(t--){ read_data(); while(true){ dfs(0); if(found) break; max_dep++; } cout << max_dep << endl; } }
思路:题目很简单,但是代码有点琐碎,节约时间,先挖个坑。

浙公网安备 33010602011771号