[kuangbin帶你飛] 專題一 簡單搜尋 個人題解
目錄
[kuangbin帶你飛] 專題一 簡單搜尋 個人題解
題解的順序就按給的順序寫吧,主要是總結一下,把之前的零散題解都刪了
棋盤問題
(這麼簡單的板子題都能卡,太弱了md)
一開始用的複雜度能高到\(O(n!)\)的DFS...後面參考了一下題解,算是懂問題出在哪了。
那個\(O(n!)\)的方法是這樣想的,整個遍歷一遍棋盤,找到適合的就做標記,回溯...我自己看著是沒什麼問題,不過最後答案就是標答的\(k!\)倍...重複計算太多了
看了一下題解,問題在這:不是遍歷整個棋盤,而是遍歷到下一行。因為棋子不能放於同一列,這一列放完了就在下一列DFS,因此不會有重複的情況。
接下來的程式碼用的是從上到下的DFS,按理論來說,從左到右,從下到上應該都行吧。
#include <bits/stdc++.h> #include <cstring> #include <iostream> using namespace std; typedef long long ll; typedef unsigned long long ull; int mod = 9973; const int INF = 0x3f3f3f3; const int maxn = 2e2 + 10; int n, k; char Map[10][10]; int xx[10], yy[10]; ll res = 0; void dfs(int y, int num) { if (num == 0) //棋子放完,答案+1 { res++; return; } for (int i = y; i < n; i++) //就是這樣,從y開始,而不是0 { for (int j = 0; j < n; j++) { if (Map[i][j] == '#' && (!xx[j]))//xx是記錄列是否有重複情況的 { xx[j] = 1; dfs(i + 1, num - 1);//DFS下一行,棋子少一個 xx[j] = 0;//回溯 } } } } int main() { while (cin >> n >> k) { res = 0; memset(xx, 0, sizeof(xx)); if (n == -1) break; for (int i = 0; i < n; i++) { cin >> Map[i]; } dfs(0, k); //從第0行開始,一開始有k個棋子要放 cout << res << endl; } return 0; } ```
Dungeon Master
三維迷宮,也就搞不清座標位置的時候會錯吧。
#include <iostream> #include <cstring> #include <queue> #include <algorithm> using namespace std; char map[35][35][35]; int visit[35][35][35]; int k,n,m,sx,sy,sz,ex,ey,ez; int to[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}}; struct point { int x,y,z,step; }; int check(int x,int y,int z) { if(x<0||y<0||z<0||x>=k||y>=n||z>=m) return 1; else if(map[x][y][z]=='#') return 1; else if(visit[x][y][z]) return 1; return 0; } int bfs() { int i; point a,next; queue<point> Q; a.x=sx,a.y=sy,a.z=sz; a.step=0; visit[sx][sy][sz] = 1; Q.push(a); while(!Q.empty()) { a=Q.front(); Q.pop(); if(a.x==ex&&a.y==ey&&a.z==ez) return a.step; for(i=0;i<6;i++) { next=a; next.x=a.x+to[i][0]; next.y=a.y+to[i][1]; next.z=a.z+to[i][2]; if(check(next.x,next.y,next.z)) continue; visit[next.x][next.y][next.z] = 1; next.step = a.step+1; Q.push(next); } } return 0; } int main() { int i,j,r; while((cin>>k>>n>>m)&&(n+m+k)!=0) { for(i=0;i<k;i++) { for(j=0;j<n;j++) { for(r = 0; r<m; r++) { cin>>map[i][j][r]; if(map[i][j][r] == 'S') { sx = i,sy = j,sz = r; } else if(map[i][j][r] == 'E') { ex = i,ey = j,ez = r; } } } } memset(visit,0,sizeof(visit)); int fin; fin = bfs(); if(fin) cout<<"Escaped in "<<fin<<" minute(s)."<<endl; else cout<<"Trapped!"<<endl; } return 0; }
Catch That Cow
BFS很簡單,有三種方向,按BFS板子走一遍就行了
//#include <bits/stdc++.h>
#include <cstring>
#include <iostream>
#include <set>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3;
const int maxn = 1e5 + 10;
int vis[maxn];//檢測是否來過,來過了再走一遍就沒意義了
int n, k;
struct node
{
int step;
int x;
};//這道題要記錄步數,所以用結構體
int main()
{
cin >> n >> k;
if (k <= n)
{
cout << n - k;//後退只有一種方法
return 0;
}
queue<node> q;
node tem;
tem.step = 0;
tem.x = n;
q.push(tem);
vis[n] = 1;
while (!q.empty())
{
node t = q.front();
q.pop();
node t1, t2, t3;
t1.step = t2.step = t3.step = t.step + 1;
t1.x = t.x - 1, t2.x = t.x + 1, t3.x = t.x * 2;
if (t1.x == k || t2.x == k || t3.x == k)
{
cout << t1.step;
return 0;
}
if (t1.x >= 0 && (!vis[t1.x]))
{
q.push(t1);
vis[t1.x] = 1;
}
if (!vis[t2.x])
{
q.push(t2);
vis[t2.x] = 1;
}
if (t3.x < maxn && (!vis[t3.x]))
{
q.push(t3);
vis[t3.x] = 1;
}
}
return 0;
}
Fliptile
狀態壓縮啥的是真不會...先欠著吧
Find The Multiple
DFS和BFS應該都行,這次我寫了個DFS,嗯....感覺比BFS容易翻車
0101010..的話就只有兩種情況:x*10和x*10+1,不過要注意不能超過ull的範圍,一旦超了就不能輸出正確答案,就很奇怪,按理來說超了也應該可以的啊...
#include <iostream>
#include <set>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4 + 10;
int flag = 0;
int n;
void dfs(ull x, int cnt)
{
if (flag || cnt > 19)
return;
if (x % n == 0)
{
flag = 1;
cout << x << endl;
return;
}
dfs(x * 10, cnt + 1);
dfs(x * 10 + 1, cnt + 1);
}
int main()
{
while (cin >> n && n)
{
flag = 0;
dfs(1, 0);
}
return 0;
}
Prime Path
和一般的bfs走迷宮差不多,要注意的就是提前先判斷素數,還有bfs的方向是4*10,兩個迴圈就可以了。
#include <iostream>
#include <set>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4 + 10;
int num[maxn];
int vis[maxn];
int f(int x)
{
for (int i = 2; i < x; i++)
if (x % i == 0)
return 0;
return 1;
}
void solve()
{
int i;
for (i = 1000; i < 10000; i++)
{
if (f(i))
num[i] = 1;
}
}
struct node
{
int x, cnt;
node(int x, int cnt) : x(x), cnt(cnt) {}
};
int bfs(int a, int b)
{
queue<node> q;
vis[a] = 1;
if (a == b)
return 0;
node t(a, 0), r(0, 0);
q.push(t);
while (!q.empty())
{
t = q.front(), q.pop();
r.cnt = t.cnt + 1;
int mult = 1;
for (int k = 1; k <= 4; k++)
{
int tem = t.x % (mult * 10);
tem /= mult;
//cout << tem << '\n';
for (int i = 0; i < 10; i++)
{
r.x = t.x - tem * mult;
r.x += mult * i;
if (r.x == b)
return r.cnt;
if (!vis[r.x] && num[r.x])
{
vis[r.x] = 1;
q.push(r);
}
}
mult *= 10;
}
}
return -1;
}
int main()
{
solve();
int T;
int a, b;
cin >> T;
while (T--)
{
memset(vis, 0, sizeof(vis));
cin >> a >> b;
int tem = bfs(a, b);
if (tem == -1)
cout << "Impossible" << endl;
else
cout << tem << endl;
}
return 0;
}
Shuffle'm Up
沒什麼說的,模擬吧。用map交了幾次wa也不知道什麼原因,set就好了
#include <iostream>
#include <set>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 10;
string a, b, c, ans;
int T, n;
int main()
{
int Case = 1;
cin >> T;
while (T--)
{
set<string> s;
int flag = 1;
ans = "";
cin >> n >> a >> b >> c;
int cnt = 0;
while (1)
{
cnt++;
ans = "";
for (int i = 0; i < n; i++)
ans = ans + b[i] + a[i];
if (ans == c)
{
flag = 0;
break;
}
if (s.find(ans) != s.end())
break;
else
s.insert(ans);
a = ans.substr(0, n);
b = ans.substr(n);
}
if (flag)
cout << Case++ << ' ' << -1 << endl;
else
cout << Case++ << ' ' << cnt << endl;
}
return 0;
}
Pots
這題就是個非常可樂的加強版,還要再輸出路徑
我個人寫的方法又是那種極端繁瑣,試圖用bfs回溯的方式寫,估計哪些地方又沒考慮到,瘋狂wa。
看了別人題解,照他的方式搞了下路徑(其實抄了怎麼搞路徑,其他也就沒剩什麼了...)。先把回溯的方法記一下,以後再看吧。順帶一提他這種存佇列的方式比較直觀,以後再學習學習。
#include <string>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 10;
int a, b, c;
int flag = 1;
string str[] = {"", "FILL(1)", "FILL(2)", "DROP(1)", "DROP(2)", "POUR(1,2)", "POUR(2,1)"};
int vis[maxn][maxn];
struct node
{
int x, y;
int cnt;
string s;
node(int x, int y, int cnt, string s) : x(x), y(y), cnt(cnt), s(s) {}
};
void bfs()
{
vis[0][0] = 1;
queue<node> q;
node t(0, 0, 0, "0");
q.push(node(0, 0, 0, "0"));
while (!q.empty())
{
node t = q.front();
q.pop();
if (t.y == c || t.x == c)
{
flag = 0;
cout << t.cnt << endl;
for (int i = 1; i < t.s.length(); i++)
cout << str[t.s[i] - '0'] << endl;
return;
}
if (!vis[a][t.y])
{
vis[a][t.y] = 1;
q.push(node(a, t.y, t.cnt + 1, t.s + "1"));
}
if (!vis[t.x][b])
{
vis[t.x][b] = 1;
q.push(node(t.x, b, t.cnt + 1, t.s + "2"));
}
if (!vis[0][t.y])
{
vis[0][t.y] = 1;
q.push(node(0, t.y, t.cnt + 1, t.s + "3"));
}
if (!vis[t.x][0])
{
vis[t.x][0] = 1;
q.push(node(t.x, 0, t.cnt + 1, t.s + "4"));
}
if (t.x != 0 && t.y < b)
{
int tem = min(t.x, b - t.y);
if (!vis[t.x - tem][t.y + tem])
{
vis[t.x - tem][t.y + tem] = 1;
q.push(node(t.x - tem, t.y + tem, t.cnt + 1, t.s + "5"));
}
}
if (t.y != 0 && t.x < a)
{
int tem = min(t.y, a - t.x);
if (!vis[t.x + tem][t.y - tem])
{
vis[t.x + tem][t.y - tem] = 1;
q.push(node(t.x + tem, t.y - tem, t.cnt + 1, t.s + "6"));
}
}
}
}
int main()
{
cin >> a >> b >> c;
bfs();
if (flag)
cout << "impossible" << endl;
return 0;
}
錯的程式碼也記一下吧
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 10;
int a, b, c;
struct node
{
int a, b;
int pa, pb;
int op, i, j;
};
void copy(node &x, node &y)
{
x.a = y.a;
x.b = y.b;
x.i = y.i;
x.j = y.j;
x.op = y.op;
x.pa = y.pa;
x.pb = y.pb;
}
node res[maxn][maxn];
int vis[maxn][maxn];
void init()
{
memset(res, 0, sizeof(res));
memset(vis, 0, sizeof(vis));
}
int main()
{
cin >> a >> b >> c;
vector<node> v;
v.clear();
vis[0][0] = 1;
res[0][0].op = -1;
node t, r;
t.a = t.b = 0;
t.pa = t.pb = -1;
t.op = -1;
if (c == 0)
{
cout << 0 << endl;
return 0;
}
queue<node> q;
q.push(t);
while (!q.empty())
{
t = q.front();
if (t.a == c || t.b == c)
break;
q.pop();
copy(r, t);
r.pa = t.a, r.pb = t.b;
//FILL
r.op = 1;
r.a = a;
if (!vis[r.a][r.b])
{
r.i = 1;
copy(res[r.a][r.b], r);
q.push(r);
vis[r.a][r.b] = 1;
}
r.a = t.a, r.b = b;
if (!vis[r.a][r.b])
{
r.i = 2;
copy(res[r.a][r.b], r);
q.push(r);
vis[r.a][r.b] = 1;
}
//DROP
r.op = 2;
r.a = t.a, r.b = t.b;
r.a = 0;
if (!vis[r.a][r.b])
{
r.i = 1;
copy(res[r.a][r.b], r);
q.push(r);
vis[r.a][r.b] = 1;
}
r.a = t.a, r.b = 0;
if (!vis[r.a][r.b])
{
r.i = 2;
copy(res[r.a][r.b], r);
q.push(r);
vis[r.a][r.b] = 1;
}
//POUR
r.op = 3;
int tem = min(b - t.b, t.a);
r.a -= tem;
r.b += tem;
if (!vis[r.a][r.b])
{
r.i = 1, r.j = 2;
copy(res[r.a][r.b], r);
q.push(r);
vis[r.a][r.b] = 1;
}
r.a = t.a, r.b = t.b;
tem = min(a - t.a, t.b);
r.a += tem;
r.b -= tem;
if (!vis[r.a][r.b])
{
r.i = 2, r.j = 1;
copy(res[r.a][r.b], r);
q.push(r);
vis[r.a][r.b] = 1;
}
}
if (t.a != c && t.b != c)
{
cout << "impossible" << endl;
return 0;
}
int cnt = 0;
while (t.op != -1)
{
cnt++;
v.push_back(t);
copy(t, res[t.pa][t.pb]);
}
cout << cnt << endl;
for (int i = v.size() - 1; i >= 0; i--)
{
if (v[i].op == 1)
cout << "FILL(" << v[i].i << ")";
else if (v[i].op == 2)
cout << "DROP(" << v[i].i << ")";
else
cout << "POUR(" << v[i].i << "," << v[i].j << ")";
cout << endl;
}
return 0;
}
Fire Game
這題讓我明白了兩件事:
- 做啥題之前都要先看資料範圍。上一道題這麼暴力的bfs是T了的,不過這題地圖就10*10,暴力就行了,
- 思路越簡單,寫的越不容易出錯。一開始思路偏了,後面再怎麼小心都很難救回來。
最開始寫的150行,感覺考慮了各個方面,寫了很久,WA。
看了題解,思路一樣。於是按題解的結構重新寫了一遍,寫的很快,不到100行,AC。
題目大意:防火燒草叢,能同時從兩個地方燒。問最短燒完時間是多少。
暴力列舉每兩個草叢,直到最少值。還要檢測一下草坪燒乾淨沒有。
(最開始我想的先判斷連通塊數量,再根據連通塊數量搞bfs...)
//#include <bits/stdc++.h>
#include <queue>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3f;
const int maxn = 1e3 + 10;
struct node
{
int x, y, cnt;
node(int x, int y, int cnt) : x(x), y(y), cnt(cnt){};
node() : x(), y(), cnt(){};
};
int n, m;
char Map[12][12];
int vis[12][12];
vector<node> v;
void init()
{
memset(vis, 0, sizeof(vis));
memset(Map, 0, sizeof(Map));
v.clear();
}
int legal(node a)
{
if (a.x >= 0 && a.x < m && a.y >= 0 && a.y < n && Map[a.y][a.x] == '#')
return 1;
return 0;
}
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
int bfs(node a, node b)
{
memset(vis, 0, sizeof(vis));
vis[a.y][a.x] = vis[b.y][b.x] = 1;
queue<node> q;
node t, r;
int res = INF;
q.push(a), q.push(b);
while (!q.empty())
{
t = q.front();
res = t.cnt;
r.cnt = t.cnt + 1;
q.pop();
for (int i = 0; i < 4; i++)
{
r.x = t.x + dx[i];
r.y = t.y + dy[i];
if (!vis[r.y][r.x] && legal(r))
{
q.push(r);
vis[r.y][r.x] = 1;
}
}
}
for (int i = 0; i < v.size(); i++)
if (Map[v[i].y][v[i].x] == '#' && vis[v[i].y][v[i].x] == 0)
return INF;
return res;
}
int main()
{
int T;
cin >> T;
for (int z = 1; z <= T; z++)
{
cin >> n >> m;
init();
for (int i = 0; i < n; i++)
cin >> Map[i];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (Map[i][j] == '#')
v.push_back(node(j, i, 0));
if (v.size() <= 1)
cout << "Case " << z << ": " << 0 << endl;
else
{
int ans = INF;
for (int i = 0; i < v.size(); i++)
for (int j = i + 1; j < v.size(); j++)
ans = min(ans, bfs(v[i], v[j]));
if (ans == INF)
cout << "Case " << z << ": " << -1 << endl;
else
cout << "Case " << z << ": " << ans << endl;
}
}
return 0;
}
Fire!
這題真挺磨我心態的...知道是bfs但就是莫名其妙出問題
題目大意:給定一系列火源,牆,人的位置。如果人能比火勢先走到邊上即可成功逃脫,問如果可以的話,求最短時間。
坑點:一系列火源。最開始傻傻的以為有多少火源就得bfs多少次,後面發現將初始點全部放進佇列裡,得到的結果也是最短的。
隨便學了下結構體的建構函式,以後寫這些可能會少個兩三行吧。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 9973;
const int INF = 0x3f3f3f3f;
const int maxn = 1e3 + 10;
int T, a, b;
struct node
{
int x, y, cnt;
node(int x, int y, int cnt) : x(x), y(y), cnt(cnt){};//兩個建構函式,如果只寫了這個,那麼直接node x;是會報錯的,所以要寫沒引數的建構函式
node() : x(), y(), cnt(){};
};
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
vector<node> v; //vector一定要記得清空啊
char Map[maxn][maxn];
int vis[maxn][maxn];
int Fres[maxn][maxn];//火源的最短時間記錄
int Jres[maxn][maxn];//人的最短時間記錄
int legal(node x)
{
if (x.x >= b || x.x < 0 || x.y >= a || x.y < 0)
return 0;
return 1;
}
void Fbfs()
{
queue<node> q;
for (int i = 0; i < v.size(); i++)
{
q.push(v[i]);
vis[v[i].y][v[i].x] = 1;
Fres[v[i].y][v[i].x] = 0;
}
node tem, t;
while (!q.empty())
{
t = q.front();
q.pop();
tem.cnt = t.cnt + 1;
for (int i = 0; i < 4; i++)
{
tem.x = t.x + dx[i];
tem.y = t.y + dy[i];
if (legal(tem) && !vis[tem.y][tem.x] && Map[tem.y][tem.x] != '#')
{
q.push(tem);
vis[tem.y][tem.x] = 1;
Fres[tem.y][tem.x] = tem.cnt;
}
}
}
}
void Jbfs(node x)
{
vis[x.y][x.x] = 1;
queue<node> q;
node tem;
Jres[x.y][x.x] = 0;
q.push(x);
while (!q.empty())
{
x = q.front();
q.pop();
tem.cnt = x.cnt + 1;
for (int i = 0; i < 4; i++)
{
tem.x = x.x + dx[i];
tem.y = x.y + dy[i];
if (legal(tem) && !vis[tem.y][tem.x] && Map[tem.y][tem.x] != '#')
{
q.push(tem);
vis[tem.y][tem.x] = 1;
Jres[tem.y][tem.x] = tem.cnt;
}
}
}
}
void init()
{
v.clear();
memset(Map, 0, sizeof(Map));
memset(vis, 0, sizeof(vis));
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
Fres[i][j] = Jres[i][j] = INF;
}
int main()
{
cin >> T;
while (T--)
{
node J;
cin >> a >> b;
init();
for (int i = 0; i < a; i++)
cin >> Map[i];
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
{
if (Map[i][j] == 'J')
J.x = j, J.y = i, J.cnt = 0, Jres[i][j] = 0;
if (Map[i][j] == 'F')
{
v.push_back(node(j, i, 0));
Fres[i][j] = 0;
}
if (Map[i][j] == '#')
Fres[i][j] = INF, Jres[i][j] = INF;
}
}
Jbfs(J);
memset(vis, 0, sizeof(vis));
Fbfs();
int res;
res = INF;
/*for (int i = 0; i < a; i++) //列印一下方便找錯
{
for (int j = 0; j < b; j++)
cout << setw(16) << Fres[i][j];
cout << endl;
}
cout << endl;
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
cout << setw(16) << Jres[i][j];
cout << endl;
}*/
for (int i = 0; i < b; i++)
{
if (Fres[0][i] > Jres[0][i])
res = min(res, Jres[0][i]);
if (Fres[a - 1][i] > Jres[a - 1][i])
res = min(res, Jres[a - 1][i]);
}
for (int i = 0; i < a; i++)
{
if (Fres[i][0] > Jres[i][0])
res = min(res, Jres[i][0]);
if (Fres[i][b - 1] > Jres[i][b - 1])
res = min(res, Jres[i][b - 1]);
}
if (res != INF)
cout << res + 1 << endl;
else
cout << "IMPOSSIBLE" << endl;
}
return 0;
}
迷宮問題
板子題,不過題解忘了是不是我自己寫的了,好久以前交的
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
int maze[5][5];
int vis[5][5];
pair<int, int> father[5][5];
void BFS()
{
queue<pair<int, int> > q;
q.push(make_pair(0, 0));
vis[0][0] = 1;
while(!q.empty())
{
pair<int, int> p = q.front();
q.pop();
if(p.first==4 && p.second==4) break;
for (int i = 0; i < 4; ++i) {
int nx = p.first+dx[i];
int ny = p.second+dy[i];
if( 0<=nx && nx<5
&& 0<=ny && ny<5
&& maze[nx][ny]==0
&& vis[nx][ny]==0)
{
q.push(make_pair(nx, ny));
vis[nx][ny] = 1;
father[nx][ny] = p; // 當前結點(nx, ny)的父親是q
}
}
}
}
int main()
{
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
cin >> maze[i][j];
vis[i][j] = 0;
}
}
BFS();
stack<pair<int, int> > res;
pair<int, int> exit = father[4][4];
while( !(exit.first==0 && exit.second==0) )
{
res.push(exit);
exit = father[exit.first][exit.second];
}
cout << "(0, 0)" << endl;
while( !res.empty() )
{
cout << "(" << res.top().first << ", " << res.top().second << ")" << endl;
res.pop();
}
cout << "(4, 4)" << endl;
return 0;
}
Oil Deposits
記得沒錯的話是個求連通塊的題吧,板子題+1
#include <iostream>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
char map[200][200];
int dir[8][2]={{1,1},{-1,-1},{1,-1},{-1,1},{1,0},{-1,0},{0,1},{0,-1}};
int h,l;
int fin=0;
struct point
{
int x,y;
};
void bfs(int x,int y)
{
point tem,t;
tem.x=x,tem.y=y;
queue<point> q;
q.push(tem);
while (!q.empty())
{
tem=q.front();
q.pop();
for (int i=0;i<8;i++)
{
t.x=tem.x+dir[i][0];
t.y=tem.y+dir[i][1];
if (map[t.x][t.y]=='@')
{
q.push(t);
map[t.x][t.y]='*';
}
}
}
fin++;
}
int main()
{
while (cin>>h>>l&&(h!=0||l!=0))
{
memset(map,'*',sizeof(map));
fin=0;
for (int i=1;i<=h;i++)
{
for (int j=1;j<=l;j++)
{
cin>>map[i][j];
}
}
for (int i=1;i<=h;i++)
{
for (int j=1;j<=l;j++)
{
if (map[i][j]=='@')
{
bfs(i,j);
}
}
}
cout<<fin<<'\n';
}
return 0;
}
非常可樂
看了一下題解,應該有找規律版本的,不過我還是寫的bfs(也只會這個)。
最開始有兩個地方有點問題,一是忘了每組資料前要清空vis陣列,二是全寫在主函式裡,可能輸出有重複還是什麼原因,一直wa。最後寫了個函式過了。
還有,中途看了下題解,發現這題不需要開三維陣列來儲存vis,有一維是可以推出來的,所以兩維就夠了。虧我之前一直想用set來存狀態...
程式碼大概意思就是,在一次倒可樂過程中,只有六種方式,按走迷宮的方式寫就行了。唯一要注意的是邊界條件。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int mod = 998244353;
const int INF = 0x3f3f3f3f;
const int maxn = 2e2 + 10;
bool vis[110][110];
struct node
{
int s, n, m;
int cnt;
};
int s, n, m;
int bfs()
{
queue<node> q;
node tem, t;
tem.cnt = 0, tem.s = s, tem.n = 0, tem.m = 0;
vis[0][0] = 1;
q.push(tem);
while (!q.empty())
{
tem = q.front();
q.pop();
t.cnt = tem.cnt + 1;
if (tem.s == s / 2 && tem.n == s / 2)
return tem.cnt;
if (tem.s != 0)
{
if (tem.n != n)
{
int a = min(tem.s, n - tem.n);
t.s = tem.s - a;
t.n = tem.n + a;
t.m = tem.m;
if (!vis[t.n][t.m])
q.push(t), vis[t.n][t.m] = 1;
}
if (tem.m != n)
{
int a = min(tem.s, m - tem.m);
t.s = tem.s - a;
t.n = tem.n;
t.m = tem.m + a;
;
if (!vis[t.n][t.m])
q.push(t), vis[t.n][t.m] = 1;
}
}
if (tem.n != 0)
{
if (tem.s != s)
{
int a = min(tem.n, s - tem.s);
t.s = tem.s + a;
t.n = tem.n - a;
t.m = tem.m;
if (!vis[t.n][t.m])
q.push(t), vis[t.n][t.m] = 1;
}
if (tem.m != m)
{
int a = min(tem.n, m - tem.m);
t.s = tem.s;
t.n = tem.n - a;
t.m = tem.m + a;
if (!vis[t.n][t.m])
q.push(t), vis[t.n][t.m] = 1;
}
}
if (tem.m != 0)
{
if (tem.s != s)
{
int a = min(tem.m, s - tem.s);
t.s = tem.s + a;
t.n = tem.n;
t.m = tem.m - a;
if (!vis[t.n][t.m])
q.push(t), vis[t.n][t.m] = 1;
}
if (tem.n != n)
{
int a = min(tem.m, n - tem.n);
t.s = tem.s;
t.n = tem.n + a;
t.m = tem.m - a;
if (!vis[t.n][t.m])
q.push(t), vis[t.n][t.m] = 1;
}
}
}
return 0;
}
int main()
{
while (~scanf("%d %d %d", &s, &n, &m) && s)
{
memset(vis, 0, sizeof(vis));
if (s % 2)
{
cout << "NO" << endl;
continue;
}
if (n < m)
swap(n, m);
int res = bfs();
if (res)
cout << res << endl;
else
cout << "NO" << endl;
}
return 0;
}
Find a way
題目大意:兩個人要見面。求總共需要的最短時間。
程式碼第一版:就真的兩次bfs。最開始錯了一次,因為有可能其中一個人到不了某個KFC。也沒寫個什麼函式,看起來挺長,但真的就是重複兩次bfs。下一版試試同時bfs,應該是叫雙向雙搜吧。
#include <bits/stdc++.h>
using namespace std;
#define re1(i, a, b) for (int i = a; i < b; ++i)
#define re2(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
typedef unsigned long long ull;
int mod = 998244353;
const int INF = 0x3f3f3f3f;
const int maxn = 2e2 + 10;
struct node
{
int x, y;
int step;
};
int n, m;
char Map[maxn][maxn];
int vis[maxn][maxn];
int res[maxn][maxn];
int test[maxn][maxn];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
int legal(node x)
{
if (x.x < 0 || x.x >= m || x.y < 0 || x.y >= n)
return 0;
return 1;
}
int main()
{
while (~scanf("%d %d", &n, &m) && n)
{
memset(res, 0, sizeof(res));
memset(vis, 0, sizeof(vis));
memset(test, 0, sizeof(test));
for (int i = 0; i < n; i++)
scanf("%s", Map[i]);
node Y, M;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (Map[i][j] == 'Y')
Y.x = j, Y.y = i, Y.step = 0;
if (Map[i][j] == 'M')
M.x = j, M.y = i, M.step = 0;
}
}
queue<node> q;
q.push(Y);
vis[Y.y][Y.x] = 1;
while (!q.empty())
{
node tem = q.front();
q.pop();
node t;
for (int i = 0; i < 4; i++)
{
t.x = tem.x + dx[i];
t.y = tem.y + dy[i];
t.step = tem.step + 1;
if (!vis[t.y][t.x] && Map[t.y][t.x] != '#' && legal(t))
{
test[t.y][t.x]++;
res[t.y][t.x] += t.step;
vis[t.y][t.x] = 1;
q.push(t);
}
}
}
q.push(M);
memset(vis, 0, sizeof(vis));
vis[M.y][M.x] = 1;
while (!q.empty())
{
node tem = q.front();
q.pop();
node t;
for (int i = 0; i < 4; i++)
{
t.x = tem.x + dx[i];
t.y = tem.y + dy[i];
t.step = tem.step + 1;
if (!vis[t.y][t.x] && Map[t.y][t.x] != '#' && legal(t))
{
test[t.y][t.x]++;
res[t.y][t.x] += t.step;
vis[t.y][t.x] = 1;
q.push(t);
}
}
}
vector<int> rr;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (Map[i][j] == '@' && test[i][j] == 2)
rr.push_back(res[i][j]);
//cout << setw(5) << res[i][j];
}
//cout << endl;
}
sort(rr.begin(), rr.end());
cout << rr[0] * 11 << endl;
}
return 0;
}