[kuanbin帶我飛]的專題1---簡單搜索

昨天做完最後一題就已經1點了,所以就連着今天的題目一起更。

Prime Path POJ - 3126

The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-digit room numbers on their offices.
— It is a matter of security to change such things every now and then, to keep the enemy in the dark.
— But look, I have chosen my number 1033 for good reasons. I am the Prime minister, you know!
— I know, so therefore your new number 8179 is also a prime. You will just have to paste four new digits over the four old ones on your office door.
— No, it’s not that simple. Suppose that I change the first digit to an 8, then the number will read 8033 which is not a prime!
— I see, being the prime minister you cannot stand having a non-prime number on your door even for a few seconds.
— Correct! So I must invent a scheme for going from 1033 to 8179 by a path of prime numbers where only one digit is changed from one prime to the next prime.

Now, the minister of finance, who had been eavesdropping, intervened.
— No unnecessary expenditure, please! I happen to know that the price
of a digit is one pound. — Hmm, in that case I need a computer
program to minimize the cost. You don’t know some very cheap software
gurus, do you? — In fact, I do. You see, there is this programming
contest going on… Help the prime minister to find the cheapest prime
path between any two given four-digit primes! The first digit must be
nonzero, of course. Here is a solution in the case above.

1033 1733 3733 3739 3779 8779 8179 The cost of this solution is
6 pounds. Note that the digit 1 which got pasted over in step 2 can
not be reused in the last step – a new 1 must be purchased.
在這裏插入圖片描述

這道題的大意是一個首相閒着無聊找樂子,給出兩個數,使得第一個數可以通過若干次變換,每次變換隻能改變一個數字,最後變成第二個數,這變換過程每一個數字都必須是素數。
既然他要求是素數,而且查找量有些大,那我們可以打表,先預處理1000-10000之間的數,找到素數並標記。然後我們就用bfs找到到達第二個數的最少次數,在壓入棧的時候,這裏我們需要對4位數字都進行遍歷,需要注意的是,千位數字不能爲0,個位數字我們也可以判斷只能是奇數,所以可以直接+=2;如果他是素數並且沒有壓入棧過,那麼我們就把它壓入棧。當到達第二個數字的時候就返回,這裏我們需要知道的是,在隊列裏,是先進先出,所以第一個達到的肯定就是最短次數。詳細代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<vector>
#define INF 0x3f3f3f3f
# define LOCAL
using namespace std;
const int maxn = 10005;
const int N = 10;
int a[maxn];//保存變換次數,下標是數字 
int d[N]={0,1,2,3,4,5,6,7,8,9};//數字變化 
int x,y,n;
bool is_prime[maxn];//判斷是否是素數 
bool vis[maxn];//判斷是否壓入棧過 
void prime(){
	memset(is_prime,0,sizeof(is_prime));
	for(int i=1000;i<=maxn;i++){
		int p = sqrt(i);
		for(int j=2;j<=p;j++)
			if(i%j==0){
				is_prime[i] = 1;
				break;
			}
	}
}//預處理數組,要用的時候直接查表 
void bfs(){
	queue<int> q;
	q.push(x);
	vis[x] = true;
	a[x] = 0;
	while(!q.empty()){
		int temp = q.front();
		q.pop();
		if(temp == y){
			cout << a[y] << endl;
			return;
		}
		int k;
		for(int i=1;i<N;i++){//千位,千位不能爲0 
			k = temp%1000 + i*1000;
			if(!is_prime[k] && !vis[k]){
				q.push(k);
				vis[k] = true;
				a[k] = a[temp] + 1;
			}
		}
		for(int i=0;i<N;i++){//百位 
			k = temp/1000 * 1000 + temp%100 + i*100;
			if(!is_prime[k] && !vis[k]){
				q.push(k);
				vis[k] = true;
				a[k] = a[temp] + 1;
			}
		}
		for(int i=0;i<N;i++){//十位 
			k = temp/100 * 100 + temp%10 + i*10;
			if(!is_prime[k] && !vis[k]){
				q.push(k);
				vis[k] = true;
				a[k] = a[temp] + 1;
			}
		}
		for(int i=1;i<N;i+=2){//個位,個位只能是奇數 
			k = temp/10 * 10 + i;
			if(!is_prime[k] && !vis[k]){
				q.push(k);
				vis[k] = true;
				a[k] = a[temp] + 1;
			}
		}
	}
	cout << "Impossible" << endl;//沒有到達最後 
	return;
}
int main(){
std::ios::sync_with_stdio(false);  
#ifdef LOCAL
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	cin >> n;
	prime();//預處理 
	while(n--){
		cin >> x >> y;
		memset(vis,false,sizeof(vis));//初始化 
		bfs();
	}
	return 0;
}

Shuffle’m Up POJ - 3087

在這裏插入圖片描述
這道題的大意是給三個字符串,其中前面兩個字符串先按照第二個字符串最下的字符在新字符串最下面,最上面的字符是第一個字符串的最下的字符,類似交替排序,如果和第三個字符串不相同,則將下面一半作爲新的s1,上面一半作爲新的s2,再繼續上面的操作,直到和第三個字符串一樣。
這裏我們需要注意的是,如果我們直接這樣設計程序會陷入死循環,因爲如果到不了第三個字符串的序列,到一定次數的時候,新字符串會重複出現。所以我們需要記錄出現過的每一個新字符串,然後每次都對新字符串進行判斷,如果有相同的,則證明無法到達第三個字符串序列,直接返回。這裏有些人用map來作爲標記,這樣比我的節省了很多空間,不過我用字符數組所以就直接耶同樣用字符數組存儲。詳細代碼如下:

//模擬 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define INF 0x3f3f3f3f
# define LOCAL
using namespace std;
const int maxn = 105;
char s1[maxn],s2[maxn],tmp[maxn*2],s[maxn*2],bol[1005][maxn*2];//bol數組存儲已經整合過的字符串 
int len,ans;//ans存儲答案 

bool judge(){
	for(int i=0;i<ans+1;i++)
		if(!strcmp(bol[i],tmp))
			return true;
	return false;	
}//判斷是否已存儲字符串 
bool bfs(){
	memset(bol,'0',sizeof(bol));
	int l = 0;
	for(int i=0;i<len;i++){
		tmp[l++] = s2[i];
		tmp[l++] = s1[i];
	}
	tmp[l] = '\0';//結束符!!!! 
	ans = 0;
	while(!judge()){
		strcpy(bol[ans],tmp);
		ans++;
		if(!strcmp(tmp,s))
			return true;
		for(int i=0;i<len;i++){
			s1[i] = tmp[i];
			s2[i] = tmp[len+i];
		}
		l = 0;
		for(int i=0;i<len;i++){
			tmp[l++] = s2[i];
			tmp[l++] = s1[i];
		}
		tmp[l] = '\0';//結束符!!!! 
	}
	return false;
}
int main(){
std::ios::sync_with_stdio(false);  
#ifdef LOCAL
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	int n;
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> len;
		cin >> s1 >> s2 >> s;
		cout << i << " ";
		if(bfs())
			cout << ans << endl;
		else
			cout << "-1" << endl;
	}
	return 0;
}

Pots POJ - 3414

在這裏插入圖片描述
這道題是倒水問題,有倒水的規則。同樣是用bfs解題。這裏想要提一下的是,如何記錄在查找過程中的各個操作,因爲題目最後要求要輸出操作,所以我們先用一個二維字符數組將所有操作存儲起來,然後再bfs,進棧出棧的過程中記錄所對應的下標,這裏我用到的是在結構體裏多定義一個記錄操作的字符數組用來記錄每一步的路徑,其中下標表示是第幾步,對應的字符則是以字符形式存儲的操作的下標。在每一次壓入棧的時候,我們都需要將上一步操作的字符數組複製下來,並將當前的操作下標存進去。

#include<cstdio>
#include<cstring>
#include<queue>
# define LOCAL
using namespace std;
const int maxn = 105;
const int N = 10;
int a,b,c;
bool vis[maxn][maxn];//判斷是否已經出現這種情況 
char str[N][N] = {"","FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};//輸出的字符串 
struct node{
	int a,b;//第一瓶水和第二瓶水 
	int step;//路徑長度 
	char print[1005];//記錄路徑 
};//定義每一步的各個值 
void bfs(){
	node t={0,0,0,'0'},tmp;//初始化 
	queue<node> q;
	q.push(t);
	vis[t.a][t.b] = true;
	while(!q.empty()){
		node cur = q.front();
		q.pop();
		if(cur.a == c || cur.b == c){
			printf("%d\n",cur.step);
			for(int i=0;i<cur.step;i++)
				printf("%s\n",str[cur.print[i]-'0']);
			return;
		}//結束條件 
		for(int i=1;i<=6;i++){
			bool flag = false;
			if(i==1 && cur.a < a){//把第一個瓶子裝滿
				tmp.a = a;
				tmp.b = cur.b;
				flag = true;
			}else if(i==2 && cur.b < b){ //把第二個瓶子裝滿
				tmp.a = cur.a;
				tmp.b = b;
				flag = true;
			}else if(i==3 && cur.a!=0){//把第一個瓶子倒了
				tmp.a = 0;
				tmp.b = cur.b;
				flag = true;
			}else if(i==4 && cur.b!=0){//把第二個瓶子倒了
				tmp.a = cur.a;
				tmp.b = 0;
				flag = true;
			}else if(i==5 && cur.a!=0 && cur.b<b){//把第一個倒進第二個
				if(b-cur.b >= cur.a){
					tmp.b = cur.a + cur.b;
					tmp.a = 0;
				}else{
					tmp.a = cur.a+ cur.b - b;
					tmp.b = b;
				}
				flag = true;
			}else if(i==6 && cur.b!=0 && cur.a<a){//把第二個倒進第一個
				if(a-cur.a >= cur.b){
					tmp.a = cur.a + cur.b;
					tmp.b = 0;
				}else{
					tmp.b = cur.a + cur.b - a;
					tmp.a = a;
				}
				flag = true;
			}
			if(flag){
				if(vis[tmp.a][tmp.b])//判斷是否出現過,如果沒有出現過,則壓入棧 
					continue; 
				vis[tmp.a][tmp.b] = true;
				tmp.step = cur.step + 1;//路徑長度+1 
				strcpy(tmp.print,cur.print);//複製上一個記錄的路徑 
				tmp.print[cur.step] = i + '0';//標記當前路徑 
				q.push(tmp);				
			}
		}
	}
	printf("impossible\n");
	return;
}

int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	scanf("%d%d%d",&a,&b,&c);
	memset(vis,false,sizeof(vis));
	bfs();
	return 0;
}

非常可樂 HDU - 1495

在這裏插入圖片描述
這道題有兩種解法,我一開始只想到BFS,但發現有位大佬直接用數論寫20行代碼把它做出來了,很震驚,也研究了很久。這裏給下大佬的鏈接
超強!!
在這裏插入圖片描述
然後我也發現網上很多可能是抄這位大佬的,解析什麼都沒有,就直接把大佬的代碼複製過來,當然也可能是我太菜了.這裏我大概補充一些我原來沒有理解到的地方,關於方程轉化,可以通過約分進行簡化,其實約分後得到的就是最大公因數.然後我們可以通過移位得到x的表達式然後再進行換元,把c消掉,這樣就使得每個表達式只有一個變量,然後關於x和y,我們由通解的形式可以看出是一正一負,所以再去絕對值的時候需要注意下.

#include<cstdio>
int gcd(int n,int m){
	return m?gcd(m,n%m):n;
}
int main(){
	int s,n,m;
	while(~scanf("%d%d%d",&s,&n,&m),s+n+m){
		s /= gcd(n,m);
		if(s&1)
			printf("NO\n");
		else
			printf("%d\n",s-1);
	}
	return 0;
}

我的思路----bfs

這個其實和上一題很像,可以說只是換了一下形式,所以我第一反應就是用bfs,也沒有想其他的.,關於思路,其實也差不多,所以就寫了一些註釋以供參考.

#include<cstdio>
#include<cstring>
#include<queue>
# define LOCAL
using namespace std;
const int maxn = 105;
int v[5];
bool vis[maxn][maxn][maxn];//判斷是否已經出現這種情況 
struct node{
	int v[5];//可樂瓶、第一瓶水和第二瓶水 
	int step;//路徑長度
}tmp;//定義每一步的各個值
void pour(int i,int j){
	int sum = tmp.v[i] + tmp.v[j];
	if(sum >= v[j])
		tmp.v[j] = v[j];
	else
		tmp.v[j] = sum;
	tmp.v[i] = sum - tmp.v[j];
}
void bfs(){
	node t;//初始化
	t.v[1] = v[1],t.v[2]=t.v[3]=t.step=0;
	queue<node> q;
	q.push(t);
	vis[t.v[1]][0][0] = true;
	while(!q.empty()){
		node cur = q.front();
		q.pop();
		if(cur.v[1]==cur.v[3] && cur.v[2]==0){
			printf("%d\n",cur.step);
			return;
		}
		for(int i=1;i<4;i++)
			for(int j=1;j<4;j++){
				if(i!=j){
					tmp = cur;
					pour(i,j);
					if(!vis[tmp.v[1]][tmp.v[2]][tmp.v[3]]){
						tmp.step++;
						q.push(tmp);
						vis[tmp.v[1]][tmp.v[2]][tmp.v[3]] = true;
					}
				}
			}
	}
	printf("NO\n");
	return;
}

int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	while(~scanf("%d%d%d",&v[1],&v[2],&v[3]),v[1]+v[2]+v[3]){
		if(v[2]>v[3]){
			int t=v[2];v[2]=v[3];v[3]=t;
		}
		memset(vis,false,sizeof(vis));
		bfs();
	}

	return 0;
}

Fire! UVA - 11624

在這裏插入圖片描述
這道題的話,剛開始我以爲火源會移動,後面才直到只是向四周擴散.這裏就用到了兩次隊列.我們可以先預處理火源達到每一位置的時間,通過隊列實現.然後再看joe怎麼走,如果走的位置是在火源路徑的話,就需要判斷先後,如果joe先則可以走.詳細代碼如下:

//兩次隊列 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
# define LOCAL
using namespace std;
const int maxn = 1005;
const int inf = 0x3f3f3f3f;
int n,r,c;
int d[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};//方向 
char mp[maxn][maxn];//圖 
int firetime[maxn][maxn];//火到達某點的時間 
bool vis[maxn][maxn];//判斷是否出現過 
struct node{
	int x,y;
	int t;
}joe; 
bool judge(int x,int y){
	if(x<0 || x>=r || y<0 || y>=c)
		return false;
	return true;
}//判斷是否出界 
queue<node> q;
void init(){
	memset(vis,false,sizeof(vis));
	memset(firetime,inf,sizeof(firetime));
	while(!q.empty())
		q.pop();
	for(int i=0;i<r;i++){
		for(int j=0;j<c;j++){
			if(mp[i][j]=='J'){
				joe.x = i,joe.y = j,joe.t = 0;//找到joe位置 
			}else if(mp[i][j]=='F'){
				firetime[i][j] = 0;
				vis[i][j] = true;
				q.push((node){i,j,0});//找到火的位置並把它壓入棧 
			}
		}
	}
	while(!q.empty()){
		node cur = q.front();
		q.pop();
		for(int i=0;i<4;i++){
			int tx = cur.x + d[i][0];
			int ty = cur.y + d[i][1];
			if(judge(tx,ty) && !vis[tx][ty] && mp[tx][ty]=='.'){
				vis[tx][ty] = true;
				firetime[tx][ty] = cur.t + 1;
				q.push((node){tx,ty,cur.t+1});
			}
		}
	}//預處理火源蔓延位置的時間
}
void bfs(){
	init();
	memset(vis,false,sizeof(vis));
	while(!q.empty())
		q.pop();
	q.push(joe);
	vis[joe.x][joe.y] = true;
	while(!q.empty()){
		node cur = q.front();
		q.pop();
		for(int i=0;i<4;i++){
			int tx = cur.x + d[i][0];
			int ty = cur.y + d[i][1];
			if(!judge(tx,ty)){
				printf("%d\n",cur.t+1);
				return;
			}//判斷已出界,則證明已逃脫 
			if(!vis[tx][ty] && mp[tx][ty]=='.' && cur.t+1 < firetime[tx][ty]){
				vis[tx][ty] = true;
				q.push((node){tx,ty,cur.t+1});
			}//如果joe到達某個點的時間比火源小,則可以到達,壓入棧 
		}
	}
	printf("IMPOSSIBLE\n");
	return;//逃脫不了 
}
int main(){
std::ios::sync_with_stdio(false);  
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	cin >> n;
	while(n--){
		cin >> r >> c;
		memset(mp,'#',sizeof(mp));//初始化mp 
		for(int i=0;i<r;i++)
			cin >> mp[i];
		bfs();
	}
	return 0;
}

Oil Deposits HDU - 1241

在這裏插入圖片描述
這道其實是紫書上一模一樣的題目,所以看完題目就直接開始寫代碼了,所以也沒有註釋,這裏就再說一下吧,這道題是求聯通塊的,就是我們在找到一個油田的時候需要找到和他相鄰的油田,即同一個連通塊.這裏我們用dfs來做,我們用vis數組來標記是否是同一個聯通塊.我們先對圖裏面每一個位置進行篩選,就是找到沒有標記的油田,然後調用dfs函數,dfs函數裏再判斷它周圍的位置是否有油田,如果有的話就繼續調用dfs函數,我們這裏用cnt來表示聯通塊的個數,並作爲標記.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
# define LOCAL
using namespace std;
const int maxn = 105;
char mp[maxn][maxn];
int vis[maxn][maxn];
int n,m;
void dfs(int i,int j,int cnt){
	if(i<0 || i>=m || j<0 || j>=n)	return;
	if(mp[i][j]=='#' || vis[i][j]!=0)	return;
	vis[i][j] = cnt;
	for(int k=-1;k<=1;k++)
		for(int l=-1;l<=1;l++)
			if(mp[i+k][j+l]=='@' && vis[i+k][j+l]==0)
				dfs(i+k,j+l,cnt);
}
int main(){
std::ios::sync_with_stdio(false);  
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	while(scanf("%d%d",&m,&n)==2 && m){
		for(int i=0;i<m;i++)
			scanf("%s",&mp[i]);
		int cnt = 0;
		memset(vis,0,sizeof(vis));
		for(int i=0;i<m;i++)
			for(int j=0;j<n;j++){
				if(vis[i][j]==0 && mp[i][j]=='@')
					dfs(i,j,++cnt);
			}
		printf("%d\n",cnt);
	}
	return 0;
}

Find a way HDU - 2612

在這裏插入圖片描述
這道題是找兩個人的最短路徑,這裏其實我們可以借鑑fire的思路,即兩次隊列,先對第一個人到達每一個KFC的時間用 t數組記錄下來,然後再通過隊列得到第二個人到達每一個KFC的路徑,這裏我們用一個全局表量nmin來表示最小的路徑,因爲每段路徑時間是一樣的,即對於每一個KFC將第一個人和第二個人的路徑相加,不斷比較,最後得到最少的時間nmin*11.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
# define LOCAL
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 205;
int d[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//方向 
char mp[maxn][maxn];//圖 
bool vis[maxn][maxn];//判斷是否在前面已經出現過 
int step[maxn][maxn];//走過的街道 
int n,m;
int nmin;//走過的最小街道數 
struct node{
	int x,y;
	int step;
}v[2];//定義兩個人數據 
bool judge(int i,int j){
	if(i<0 || j<0 || i>=n || j>=m)	return false;
	if(vis[i][j] || mp[i][j]=='#')	return false;
	return true;
}//判斷是否符合條件 
queue<node> q;
void bfs(){
	memset(vis,false,sizeof(vis));//初始化 
	while(!q.empty())
		q.pop();//清空隊列 
	q.push(v[0]);//把第一個人壓入棧 
	vis[v[0].x][v[0].y] = true;//標記 
	while(!q.empty()){
		node cur = q.front();
		q.pop();
		for(int i=0;i<4;i++){
			node tmp=cur;
			tmp.x = cur.x + d[i][0];
			tmp.y = cur.y + d[i][1];//各個方向走 
			if(judge(tmp.x,tmp.y) && (mp[tmp.x][tmp.y]=='.'||mp[tmp.x][tmp.y]=='@')){
				vis[tmp.x][tmp.y] = true;
				tmp.step = cur.step + 1;//走過的街道數加一 
				if(mp[tmp.x][tmp.y]=='@')//判斷是否到達KFC 
					step[tmp.x][tmp.y] = min(step[tmp.x][tmp.y],tmp.step);
				q.push(tmp);//如果是街道繼續走,壓入棧 
			}
		}
	}
	memset(vis,false,sizeof(vis));
	while(!q.empty())
		q.pop();
	q.push(v[1]);
	vis[v[1].x][v[1].y] = true;
	while(!q.empty()){
		node cur = q.front();
		q.pop();
		for(int i=0;i<4;i++){
			node tmp=cur;
			tmp.x = cur.x + d[i][0];
			tmp.y = cur.y + d[i][1];
			if(judge(tmp.x,tmp.y) && (mp[tmp.x][tmp.y]=='.'||mp[tmp.x][tmp.y]=='@')){
				vis[tmp.x][tmp.y] = true;
				tmp.step = cur.step + 1;//走過的街道數加一 
				if(mp[tmp.x][tmp.y]=='@')//判斷是否到達KFC 
					nmin = min(step[tmp.x][tmp.y]+tmp.step,nmin);
				q.push(tmp);//如果是街道繼續走,壓入棧 
			}
		}
	}
}
int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	while(scanf("%d%d",&n,&m)==2){
		memset(step,inf,sizeof(step));
		nmin = inf;
		for(int i=0;i<n;i++){
			scanf("%s",mp[i]);
			for(int j=0;j<m;j++)
				if(mp[i][j]=='Y'){
					v[0].x = i,v[0].y = j,v[0].step=0;					
				}else if(mp[i][j] == 'M'){
					v[1].x = i,v[1].y = j,v[1].step=0;
				}
		}
		bfs();
		printf("%d\n",nmin*11);
	} 
	return 0;
}

這裏我還用了另一個方法,其實也差不多,只是把重複的代碼合在一起,調用兩次.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
# define LOCAL
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 205;
int d[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//方向 
char mp[maxn][maxn];//圖 
bool vis[maxn][maxn];//判斷是否在前面已經出現過 
int dis[maxn][maxn][2];
int n,m;
struct node{
	int x,y;
	int step;
};
bool judge(int i,int j){
	if(i<0 || i>=n || j<0 || j>=m)	return false;
	if(vis[i][j] || mp[i][j]=='#')	return false;
	return true;
}

void bfs(int x,int y,int flag){
	node cur,tmp;
	cur.x = x,cur.y = y,cur.step = 0;
	queue<node> q;
	q.push(cur);
	vis[cur.x][cur.y] = true;
	while(!q.empty()){
		cur = q.front();
		q.pop();
		for(int i=0;i<4;i++){
			tmp.x = cur.x + d[i][0];
			tmp.y = cur.y + d[i][1];
			if(judge(tmp.x,tmp.y) && (mp[tmp.x][tmp.y]=='.'||mp[tmp.x][tmp.y]=='@')){
				vis[tmp.x][tmp.y] = true;
				tmp.step = cur.step + 1;
				if(mp[tmp.x][tmp.y]=='@')
					dis[tmp.x][tmp.y][flag] = min(dis[tmp.x][tmp.y][flag],tmp.step);
				q.push(tmp);
			}
		}
	}
}
int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	while(scanf("%d%d",&n,&m)==2){
		memset(dis,inf,sizeof(dis));
		for(int i=0;i<n;i++)
			scanf("%s",mp[i]);
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++)
				if(mp[i][j]=='Y'){
					memset(vis,false,sizeof(vis));
					bfs(i,j,0);
				}else if(mp[i][j] == 'M'){
					memset(vis,false,sizeof(vis));
					bfs(i,j,1);
				}	
		}
		int ans = inf;
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				if(mp[i][j]=='@' && ans>dis[i][j][0]+dis[i][j][1])
					ans = dis[i][j][0] + dis[i][j][1];
		printf("%d\n",ans*11);
	}
	return 0;
}

題外話

今天把[kuanbin帶我飛]的專題1做完了,有一道Vjudge交不了,感覺收穫很多,繼續加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章