1. 程式人生 > 實用技巧 >[kuangbin帶你飛] 專題一 簡單搜尋 個人題解

[kuangbin帶你飛] 專題一 簡單搜尋 個人題解

目錄

[kuangbin帶你飛] 專題一 簡單搜尋 個人題解

題解的順序就按給的順序寫吧,主要是總結一下,把之前的零散題解都刪了

棋盤問題

POJ - 1321

(這麼簡單的板子題都能卡,太弱了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

POJ - 3278

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

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

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

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

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

Fire Game

這題讓我明白了兩件事:

  1. 做啥題之前都要先看資料範圍。上一道題這麼暴力的bfs是T了的,不過這題地圖就10*10,暴力就行了,
  2. 思路越簡單,寫的越不容易出錯。一開始思路偏了,後面再怎麼小心都很難救回來。
    最開始寫的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!

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

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

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;
}