簡單搜索總結--kuangbin帶你飛專題一

今天網絡賽又被虐了,哎,還是太菜,還是忘了吧,重要的是努力,是提升,黑暗總會過去的!!!希望一直都有,只要你肯堅持!從現在做起,重拾信心,重拾希望,不要企圖一步登天,不要想那些虛無縹緲的未來,腳踏實地,向前進!

現在就把前陣子寫的專題一做個總結吧。

bfs:遞歸實現,所以容易超時爆棧,而且判重、標記要麼都在中間,要麼都在開頭(根據寫法類型而定,“先判再走”or"走後再判")【見A題】。回溯恢復要麼都在本層,要麼都在下一層。【見A題】

如果題目要求最優解,找到目標後,每次還要進行比較取優。

如果題目中,每一步可以任意走的話,可以採用。

bfs:循環實現,不會爆棧。判重、標記要麼都在入隊前,要麼都在出隊後。

第一次找到目標後,就是最優解,無需比較取優。

如果題目中,每一步有規定,只能特定地走,可以採用。

可以打印路徑,只要用數組模擬隊列,並且在節點的結構體中加一個pre就行,路徑的第一個節點的pre設爲-1,打印時用一個遞歸函數,終止條件就是pre!=-1。

A題:

題意:

給你一個n*n的棋盤,棋盤上只有'#'位置可以放置棋子,要求放置k個棋子,棋子每一行,每一列只能有一個棋子。

思路:

由於n,k很小,不超過8,直接暴搜就行,看了一下自己的提交記錄,發現並不是1A,任何的非1A都可能導致一場比賽的失敗,這也暴露了自己對暴搜寫法有一定的問題。

先看一下我的AC代碼:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n,k;
char mp[10][10];
int ans;

int vis1[10];
int vis2[10]; 

void dfs(int now, int cnt){
	if(cnt == k){
		ans++;
		return;
	}
	for(int i = now; i <= n; ++i){
		if(vis1[i])	continue;
		for(int j = 1; j <= n; ++j){
			if(vis2[j])	continue;
			if(mp[i][j] == '#'){
				vis1[i] = 1;
				vis2[j] = 1;
				dfs(i+1,cnt+1);
				vis1[i] = 0;
				vis2[j] = 0;
			}
		}
	}
}


int main()
{
	#ifndef ONLINE_JUDGE
		//Fin;
	#endif // ONLINE_JUDGE
	while(scanf("%d%d",&n,&k) == 2){
		getchar();
		if(n == -1 && k == -1)	break;
		fo(i,1,n+1){
			fo(j,1,n+1)
				scanf("%c",&mp[i][j]);
			getchar();
		}

		ans = 0;
		dfs(1,0);
		printf("%d\n",ans);
	}
	return 0;
}

我上面的AC代碼就是典型的判斷後再走。

再看一下我的失敗代碼:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n,k;
char mp[10][10];
int ans;

int vis1[10];
int vis2[10]; 

void dfs(int now, int cnt){
	if(cnt == k){
		ans++;
		return;
	}
	if(vis1[now])	return;
	for(int i = now; i <= n; ++i){
		for(int j = 1; j <= n; ++j){
			if(vis2[j])	continue;
			if(mp[i][j] == '#'){
				vis1[i] = 1;
				vis2[j] = 1;
				dfs(now+1,cnt+1);
				vis1[i] = 0;
				vis2[j] = 0;
			}
		}
	}
}


int main()
{
	#ifndef ONLINE_JUDGE
		//Fin;
	#endif // ONLINE_JUDGE
	while(scanf("%d%d",&n,&k) == 2){
		getchar();
		if(n == -1 && k == -1)	break;
		fo(i,1,n+1){
			fo(j,1,n+1)
				scanf("%c",&mp[i][j]);
			getchar();
		}

		ans = 0;
		dfs(1,0);
		printf("%d\n",ans);
	}
	return 0;
}

不難發現失敗代碼與ac代碼就差別在對vis1數組的判重的位置,這告訴我,既然選擇“判斷後再走”,就必須嚴格遵循“先判重,然後走”,不能又在開頭再判重

另外,又參考了一下別人的代碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char a[10][10];
int ans=0;
int n,k;
int visit [10];
void bfs(int cnt,int x,int y)
{
    if(cnt==k) {
        ans++;
        return ;
    }
    visit[y]=1;
    for(int i=x+1;i<n;i++){
        for(int j=0;j<n;j++){
            if(visit[j]==0&&a[i][j]=='#') {
                bfs(cnt+1,i,j);
            }
        }
    }
    visit[y]=0;
}
int main()
{
 
    while(~scanf("%d%d",&n,&k)){
        if(n==-1&&k==-1) {
            break;
        }
        for(int i=0;i<n;i++) {
            scanf("%s",a[i]);
        }
        int x,y;
        ans=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(a[i][j]=='#') {
                   memset(visit,0,sizeof(visit));
                    bfs(1,i,j);
                }
            }
        }
        printf("%d\n",ans);
    }
}

他的代碼在恢復狀態的寫法與我不同(對visit數組),其實兩種方法都可以,我的放在裏面,就是等它回到原來這一層,再給恢復,而他的代碼,則是在進入下一層再標記,然後在回到本層才恢復標記

 

B題:

題意:

給一個三維的迷宮,’#‘不能走,’.'表示可以走,'S'表示起點,'E'表示終點,求最短逃離時間,若不能逃離,輸出“Trapped!”,否則輸出“Escaped in x minute(s).”。

思路:對於每一步行走有限制的題目,一般採用bfs,而每一步可以任意行走的題,例如上一題,可以採用dfs,本次採用bfs,對六個方向進行試探,入隊...

代碼1(極其冗雜易錯的代碼):

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

typedef struct Node{
	int x,y,z;
}Node;

typedef struct node{
	int step;
	Node loc;
}node;

int l,r,c;
char mp[100][100][100];
int vis[100][100][100];
Node start,end;
queue<node> que;
int ans;


void bfs(){
	while(!que.empty())
		que.pop();
	me(vis,0);
	ans = 0;
	node Begin;
	Begin.step = 0;
	Begin.loc.x = start.x;
	Begin.loc.y = start.y;
	Begin.loc.z = start.z;
	que.push(Begin);
	vis[start.z][start.x][start.y] = 1;
	while(!que.empty()){
		node now = que.front();
		que.pop();
		int step = now.step; 
		int z = now.loc.z; int x = now.loc.x; int y = now.loc.y;
		//printf("now:  step:%d z:%d x:%d y:%d\n",step,z,x,y);
		if(z == end.z && x == end.x && y == end.y){
			//printf("success!! step:%d z:%d x:%d y:%d\n",step,z,x,y);
			ans = step;
			return;
		}
		//printf("上: vis:%d mp:%c\n",vis[z+1][x][y],mp[z+1][x][y]);
		if(z+1 <= l && !vis[z+1][x][y] && mp[z+1][x][y] != '#'){
			//printf("上: step:%d z:%d x:%d y:%d\n",step+1,z+1,x,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z+1;	temp.loc.x = x; temp.loc.y = y;
			vis[z+1][x][y] = 1;
			que.push(temp);
		}
		//printf("下: vis:%d mp:%c\n",vis[z-1][x][y],mp[z-1][x][y]);
		if(z-1 >= 1 && !vis[z-1][x][y] && mp[z-1][x][y] != '#'){
			//printf("下: step:%d z:%d x:%d y:%d\n",step+1,z-1,x,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z-1;	temp.loc.x = x; temp.loc.y = y;
			vis[z-1][x][y] = 1;
			que.push(temp);
		}
		//printf("右: vis:%d mp:%c\n",vis[z][x+1][y],mp[z][x+1][y]);
		if(x+1 <= r && !vis[z][x+1][y] && mp[z][x+1][y] != '#'){
			//printf("右: step:%d z:%d x:%d y:%d\n",step+1,z,x+1,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x+1; temp.loc.y = y;
			vis[z][x+1][y] = 1;
			que.push(temp);
		}
		//printf("左: vis:%d mp:%c\n",vis[z][x-1][y],mp[z][x-1][y]);
		if(x-1 >= 1 && !vis[z][x-1][y] && mp[z][x-1][y] != '#'){
			//printf("左: step:%d z:%d x:%d y:%d\n",step+1,z,x-1,y);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x-1; temp.loc.y = y;
			vis[z][x-1][y] = 1;
			que.push(temp);
		}
		//printf("前: vis:%d mp:%c\n",vis[z][x][y+1],mp[z][x][y+1]);
		if(y+1 <= c && !vis[z][x][y+1] && mp[z][x][y+1] != '#'){
			//printf("前: step:%d z:%d x:%d y:%d\n",step+1,z,x,y+1);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x; temp.loc.y = y+1;
			vis[z][x][y+1] = 1;
			que.push(temp);
		}
		//printf("後: vis:%d mp:%c\n",vis[z][x][y-1],mp[z][x][y-1]);
		if(y-1 >= 1 && !vis[z][x][y-1] && mp[z][x][y-1] != '#'){
			//printf("後: step:%d z:%d x:%d y:%d\n",step+1,z,x,y-1);
			node temp;
			temp.step = step+1;
			temp.loc.z = z;	temp.loc.x = x; temp.loc.y = y-1;
			vis[z][x][y-1] = 1;
			que.push(temp);
		}
	}
}

int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	while(scanf("%d%d%d",&l,&r,&c) == 3){
		//printf("l:%d r:%d c:%d\n",l,r,c);
		//getchar();
		if(!l && !r && !c)	break;
		me(mp,0);
		int i,j,k;
		for(i = 1; i <= l; ++i){
			for(j = 1; j <= r; ++j){
				scanf("%s",mp[i][j]+1);
				for(k = 1; k <= c; ++k){
					if(mp[i][j][k] == 'S'){
						start.x = j; start.y= k; start.z = i;
					}
					if(mp[i][j][k] == 'E'){
						end.x = j; end.y= k; end.z = i;
					}
				}
				//getchar();
			}
			//getchar();
		}
		/*for(int i = 1; i <= l; ++i){
			for(int j = 1; j <= r; ++j){
				for(int k = 1; k <= c; ++k){
					cout << mp[i][j][k];
				}
				cout << endl;
			}
			cout << endl;
		}
		printf("start: x:%d y:%d z:%d\n",start.x, start.y, start.z);
		printf("end: x:%d y:%d z:%d\n",end.x, end.y, end.z);*/
		ans = 0;
		bfs();
		if(ans == 0)
			cout << "Trapped!" << endl;
		else
			printf("Escaped in %d minute(s).\n",ans);
	}
	return 0;
}

其實上面的bfs的代碼量可以縮短很多的,首先可以寫一個check函數,判斷點是否合理,另外,六個方向可以用三個一維數組(1*6)表示。

代碼2(簡潔代碼,其中的六個方向的表示,代碼中提供了兩種方法,個人喜歡沒被註釋掉的那種方法):

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int l,r,c;
char mp[35][35][35];
int vis[35][35][35];
//int dire[6][3] = {{0,0,1},{0,0,-1},{1,0,0},{-1,0,0},{0,1,0},{0,-1,0}};
int dirx[] = {0,0,1,-1,0,0};
int diry[] = {0,0,0,0,1,-1};
int dirz[] = {1,-1,0,0,0,0};
int stx,sty,stz,edx,edy,edz;

struct node{
	int x,y,z;
	int step;
};
queue<node> que;

void Init(){
	while(!que.empty())
		que.pop();
	me(vis,0); 
} 

int check(node temp){
	if(!(1 <= temp.z && temp.z <= l))	return 0;
	if(!(1 <= temp.x && temp.x <= r))	return 0;
	if(!(1 <= temp.y && temp.y <= c))	return 0;
	if(vis[temp.x][temp.y][temp.z])	return 0;
	if(mp[temp.z][temp.x][temp.y] == '#')	return 0;
	return 1;
}

int dfs(){
	Init();
	node startt;
	startt.x = stx, startt.y = sty, startt.z = stz;	startt.step = 0;
	que.push(startt);
	vis[stx][sty][stz] = 1;
	while(!que.empty()){
		node now = que.front();
		que.pop();
		int x = now.x; int y = now.y; int z = now.z; int step = now.step;
		if(x == edx && y == edy && z == edz){
			return step;
		}
		fo(i,0,6){
			node nextt = now;
			//nextt.x += dire[i][0];
			//nextt.y += dire[i][1];
			//nextt.z += dire[i][2];
                          nextt.x += dirx[i]; nextt.y += diry[i]; nextt.z += dirz[i];
			nextt.step++; 
			if(check(nextt)){
				que.push(nextt);
				vis[nextt.x][nextt.y][nextt.z] = 1;
			} 
		}
	}
	return 0;
}

int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	while(cin >> l >> r >> c){
		if(!l && !r && !c)	break;
		me(mp,0);
		fo(i,1,l+1){
			fo(j,1,r+1){
				scanf("%s",mp[i][j]+1);
				fo(k,1,c+1){
					if(mp[i][j][k] == 'S'){
						stx = j; sty = k; stz = i;
					}
					if(mp[i][j][k] == 'E'){
						edx = j; edy = k; edz = i;
					}
				}
			}		
		}
		
		int ans = dfs();
		if(ans)
			printf("Escaped in %d minute(s).\n",ans);
		else
			printf("Trapped!\n");
	}
	return 0;
}

C題

題意:

在一個一維空間裏,給你一個初始位置,以及一個目標位置,你有三種方式可以走,1是左移一個單位,2是右移一個單位,3是位置擴爲兩倍,要求位置在[0,1e5]之間。問到達目標位置最少需要多少步?

思路:

限定了每步只可有三種選擇,那麼選擇dfs,再注意一下邊界就行。

代碼:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 100000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct Node{
	int step,loc;
	Node(int a, int b){
		step = a;
		loc = b;
	}
};

int n,k;
int vis[maxn];
queue<Node> que;
int ans;

int check(int loc){
	if(!(0 <= loc && loc <= maxn))	return 0;
	if(vis[loc])	return 0;
	return 1;
}

void bfs(){
	Node start(0,n);
	if(n == k)
		return;
	que.push(start);
	vis[n] = 1;
	while(!que.empty()){
		Node now = que.front();
		que.pop();
		int step = now.step;  int loc = now.loc;
		//printf("step:%d loc:%d\n",step,loc);
		if(loc == k){
			ans = step;
			return ;
		}
		if(check(loc-1)){
			Node Next(step+1,loc-1);
			que.push(Next);
			//printf("loc:%d step:%d\n",Next.loc,Next.step);
			vis[loc-1] = 1;
		}
		if(check(loc+1)){
			Node Next(step+1,loc+1);
			que.push(Next);
			vis[loc+1] = 1;
		}
		if(check(loc*2)){
			Node Next(step+1,loc*2);
			que.push(Next);
			vis[loc*2] = 1;
		}
	}
} 

int main()
{
	#ifndef ONLINE_JUDGE
		//Fin;
	#endif // ONLINE_JUDGE
	cin >> n >> k;
	ans = 0;
	bfs();
	cout << ans << endl;
	return 0;
}

D題:

題意:

給N*M的01矩陣,對每一個位置,可以進行01翻轉,翻轉的同時,它的上下左右的四個位置也同時進行01翻轉。問最少需要多少次翻轉,可以使矩陣全0,輸出每個位置的翻轉次數。

思路:

首先,明確一點,每一個位置翻轉2次,將回到原狀態,翻轉3次,等同於翻轉1次,因而每個位置最多翻轉1次

另外,對於這種翻轉問題,而且是對周圍的格子有影響的翻轉,一般並不需要確定全部格子,只需確定一部分格子,剩下的格子在確定好了的格子的影響下,也將被確定。而對於本題,你只要確定第一行的格子,那麼第二行也就確定了(第二行的分佈方式得需將第一行變爲全0,就是說第一行的第i列爲1時,相應的第二行的第i列要翻轉一次),同理,第二行確定後,第三行受第二行的約束,也將確定......所以只要枚舉第一行就行,可以採用dfs,暴力枚舉第一行,對於第一行的每一個位置,進行01試探。

代碼:

#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)       scanf("%d",&n);
#define Scans(s)       scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int mp[20][20];
int temp[20][20];
int ans[20][20];
int answer[20][20];
int cnt;
int m,n;
int flag;

void flip(int x, int y){
    if(x-1 >= 1)
        temp[x-1][y] = !temp[x-1][y];
    if(x+1 <= m)
        temp[x+1][y] = !temp[x+1][y];
    if(y-1 >= 1)
        temp[x][y-1] = !temp[x][y-1];
    if(y+1 <= n)
        temp[x][y+1] = !temp[x][y+1];
    temp[x][y] = !temp[x][y];
}


int Count(){
    int sum = 0;
    fo(i,1,m+1)
        fo(j,1,n+1)
            if(ans[i][j] == 1)
                sum++;
                return sum;
}

void Copy(){
    fo(i,1,m+1)
        fo(j,1,n+1)
            answer[i][j] = ans[i][j];
}

int check(){
    for(int i = 1; i <= m; ++i){
        for(int j = 1;j <= n; ++j)
            temp[i][j] = mp[i][j];
    }
    fo(i,1,m+1){
        fo(j,1,n+1){
            if(ans[i][j] == 1)
                flip(i,j);
        }
        if(i != m){
            fo(j,1,n+1)
                ans[i+1][j] = temp[i][j];
        }
    }
    fo(i,1,m+1){
        fo(j,1,n+1){
            if(temp[i][j] == 1)
                return 0;
        }
    }
    return  1;
}


void dfs(int y){
    if(y == n){
        ans[1][y] = 0;
        if(check()){
            flag = 1;
            int num = Count();
            if(num < cnt){
                Copy();
                cnt = num;
            }
            return;
        }
        ans[1][y] = 1;
        if(check()){
            int num = Count();
            flag = 1;
            if(num < cnt){
                Copy();
                cnt = num;
            }
        }
        return;
    }
    ans[1][y] = 0;
    dfs(y+1);
    ans[1][y] = 1;
    dfs(y+1);
}

int main()
{
#ifndef ONLINE_JUDGE
    Fin;
#endif // ONLINE_JUDGE
    cin >> m >> n;
    fo(i,1,m+1)
        fo(j,1,n+1)
            cin >> mp[i][j];
    me(ans,0);
    flag = 0;
    cnt = INF;
    dfs(1);
    if(flag == 0)
        cout << "IMPOSSIBLE" << endl;
    else{
        print2();
    }
    return 0;
}

E題:

題意:

給你一個數n,要求輸出一個n的倍數m,其中m是隻有0和1的十進制數。

思路:

這題的n是不超過200,而m不超過100位,也就是10^(100),當時看了就慌了,這個m沒法用任何類型來存啊。。太大了啊。。。後來想想,n不超過200,那麼相應的m應該也不會達到100位吧,就用long long試試,然後就過了。。。

由於m只有0和1,那麼對於m的每一位進行01試探就行。DFS和BFS都行吧。

我用的bfs(雙端口bfs),另外,本題是special judge,也就是可能存在多解,輸出一個就行,所以輸出結果和樣例不同也沒事

代碼:

#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)       scanf("%d",&n);
#define Scans(s)       scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

queue<ll> que;
ll n;

void bfs(){
    while(!que.empty())
        que.pop();
    que.push(1);
    while (!que.empty()) {
        ll  temp = que.front();
        que.pop();
        if(temp%n == 0){
            cout << temp << endl;
            return;
        }
        que.push(temp*10);
        que.push(temp*10+1);
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    while(cin >> n){
        if(!n)  break;
        //printf("n:%lld\n",n);
        bfs();
    }
    return 0;

F題:

題意:

有a,b兩個質數,要求通過一些轉換,使a變爲b,每次變換,只能變換一位,而且變換後的數也得是質數,問最少變換幾次,可以得到b。a,b都是四位數。

思路:

由於只有四位數,然後每次只能改變一位數,那麼採用bfs,可以對每一位的數依次嘗試0~9,一共36種嘗試,如果改變一位數後是質數,就入隊,直到找到b。

注意點:

由於要對每一位進行改變,所以採用字符數組來存數字,方便對每一位進行操作,然後還得把字符數組表示的數字轉化爲數字,來判斷是否是質數。所以要寫一個字符數組的函數:

int chartonum(char s[]){
    int num = 0;
    for(int i = 0; i < 4; ++i){        //一個數字的越前位,越大,所以正向處理
        num = num*10 + (s[i]-'0');
    }
    return num;
}

代碼:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n;
char st[5],ed[5];
int ans;
bool notprime[10005];
int vis[10005];

struct node{
    int num;
    char numm[5];
    int step;
};

void Init(){
    memset(notprime, false, sizeof(notprime));
    notprime[0] = notprime[1] = true;
    for(int i = 2; i < 10005; ++i){
        if(!notprime[i]){
            if(i > 10005/i) continue;
            for(int j = i*i; j < 10005; j +=i)
                notprime[j] = true;
        }
    }
}

int chartonum(char s[]){
    int num = 0;
    for(int i = 0; i < 4; ++i){
        num = num*10 + (s[i]-'0');
    }
    return num;
}

void bfs(){
    queue<node> que;
    node startt;
    strcpy(startt.numm, st);
    startt.num = chartonum(st);
    startt.step = 0;
    que.push(startt);
    vis[startt.num] = 1;
    while (!que.empty()) {
        node now = que.front();
        if(strcmp(now.numm, ed) == 0){
            ans = min(ans, now.step);
            return;
        }
        que.pop();
//        printf("now: num:%d step:%d\n",now.num,now.step);
        for(int i = 0; i < 4; ++i){
            char temp[5];
            strcpy(temp, now.numm);
//            printf("i:%d temp:%s\n",i,temp);
            for(int j = 0; j < 10; ++j){
                temp[i] = '0'+j;
//                printf("j:%d temp[%d]:%c\n",j,i,temp[i]);
                if(strcmp(temp, now.numm) == 0)
                    continue;
                int tempnum = chartonum(temp);
                if(notprime[tempnum])   continue;
                if(tempnum < 1000 || tempnum > 9999)    continue;
                if(vis[tempnum])    continue;
                node nextt;
                strcpy(nextt.numm, temp);
                nextt.num = chartonum(nextt.numm);
                nextt.step = now.step+1;
                que.push(nextt);
                vis[nextt.num] = 1;
//                printf("success\n");
            }
        }
    }
}


int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    Init();
    int n;
    Scand(n);
    fo(i, 0, n){
        me(st, 0);  me(ed, 0);
        Scans(st); Scans(ed);
//        printf("st:%s\ned:%s\n",st,ed);
        ans = INF;
        me(vis, 0);
        bfs();
        printf("%d\n",ans);
    }
    return 0;
}

G題:

題意:

類似於洗牌,給你兩個字符串s1,s2,將s1,s2交叉插入,形成一個新字符串s,問能否得到給定的字符串。

思路:

由於整個過程都是固定唯一的,可以直接模擬這個過程,每次操作完,判斷是否達到要求就行。其實就是一個遞歸函數,算不上dfs,好吧好吧,其實dfs不就是暴力遞歸嗎。。。不過有一個問題就是,既然是遞歸,那麼總得有一個終止條件吧,手算髮現,經過一定次數的操作之後,s1,s2會回到一開始的s1,s2,那麼以此作爲終止條件就行。

技巧:

將s分割爲s1和s2時,採用了strncpy函數。strncpy(字符數組名稱,起始位置,切割長度)

代碼:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e2 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

char a[maxn], b[maxn], c[2*maxn], together[2*maxn];
int success,cnt;

void fun(char a[], char b[]){
    int len = strlen(a);
    char temp[maxn*2];
    int ind = 0;
    for(int i = 0; i < len; ++i)
        together[ind++] = b[i], together[ind++] = a[i];
//    printf("temp:%s\n",temp);
//    return temp;
}

void dfs(char x[], char y[]){
//    printf("before:x:%s\ny:%s\n",x,y);
//    printf("a:%s\nb:%s\nc:%s\n",a,b,c);
    if(strcmp(x, a) == 0 && strcmp(y, b) == 0 && cnt){
        return;
    }
//    char* together;
    fi(together, maxn-5, 0);
    fun(x, y);
    cnt++;
//    printf("together:%s\n",together);
    if(strcmp(together, c) == 0){
        success = 1;
        return;
    }
    int len = strlen(together);
    strncpy(x, together, len/2);    strncpy(y, together+len/2, len/2);
//    printf("after:x:%s\ny:%s\n",x,y);
    dfs(x, y);
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    int T;
    Scand(T);
    for(int i = 1; i <= T; ++i){
        fi(a, maxn-5, 0);   fi(b, maxn-5, 0);   fi(c, maxn-5, 0);   fi(together, maxn-5, 0);
        int n;
        Scand(n);
        Scans(a), Scans(b), Scans(c);
        success = 0, cnt = 0;
//        printf("a:%s\nb:%s\nc:%s\n",a,b,c);
        char aa[maxn],bb[maxn];
        strcpy(aa, a);  strcpy(bb, b);
        dfs(aa,bb);
        if(success){
            printf("%d %d\n",i,cnt);
        }else{
            printf("%d %d\n",i,-1);
        }
    }
    return 0;
}

H題:

題意:

給你兩個容器,分別能裝下A升水和B升水,並且可以進行以下操作

FILL(i)        將第i個容器從水龍頭裏裝滿(1 ≤ i ≤ 2);

DROP(i)        將第i個容器抽乾

POUR(i,j)      將第i個容器裏的水倒入第j個容器(這次操作結束後產生兩種結果,一是第j個容器倒滿並且第i個容器依舊有剩餘,二是第i個容器裏的水全部倒入j中,第i個容器爲空)

現在要求你寫一個程序,來找出能使其中任何一個容器裏的水恰好有C升,找出最少操作數並給出操作過程

思路:

在結構體中設置兩個變量來表示兩個瓶子中當前的水量。用bfs來遍歷所有的可能,每一步有三種可能的操作。

另外由於要輸出路徑,所以要用數組模擬隊列,並在結構體中設置了pre,路徑中的第一個節點,也就是第一個入隊的節點,將其的pre設爲-1,之後入隊的節點的pre設爲父節點的數組下標。最後用遞歸函數打印路徑,遞歸的終止條件是pre==-1。

還有就是由於選擇第一種操作兩種可能,所以進入循環前,要先push兩個節點,也就是雙入口bfs。

代碼:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e6 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int id,order;
    int step,resultt1,resultt2;
    int pre;
};

node que[maxn];
int a,b,c;
int cnt = 0;
int success;
int vis[1000][1000];

void print(int num){
    if(num == -1){
        return;
    }
    print(que[num].pre);
    if(que[num].order == 1){
        printf("FILL(%d)\n",que[num].id);
    }
    else if(que[num].order == 2){
        printf("DROP(%d)\n",que[num].id);
    }else if(que[num].order == 3){
        printf("POUR(%d,%d)\n",que[num].id,3-que[num].id);
    }
}

void bfs(){
    me(que, 0); me(vis, 0); success = 0;
    node startt;
    startt.order = 1;   startt.id = 1; startt.pre = -1; startt.step = 1;    startt.resultt1 = a; startt.resultt2 = 0;
    int front = 0, rear = 0;
    que[rear++] = startt;
    startt.id = 2;  startt.resultt2 = b;    startt.resultt1 = 0;
    que[rear++] = startt;
    vis[0][0] = 1;
    int flag = 0;
    while (front < rear) {
        node now = que[front];
        if(now.resultt1 == c || now.resultt2 == c){
            success = 1;
            printf("%d\n",now.step);
            print(front);
            return ;
        }
        if(vis[now.resultt1][now.resultt2]){
            front++;
            continue;
        }
        vis[now.resultt1][now.resultt2] = 1;
            if(now.resultt1 != a){
                node nextt;
                nextt.id = 1; nextt.order = 1; nextt.pre = front; nextt.resultt1 = a; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
                que[rear++] = nextt;
            }
            if(now.resultt1 != 0){
                node nextt;
                nextt.id = 1; nextt.order = 2; nextt.pre = front; nextt.resultt1 = 0; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
                que[rear++] = nextt;
            }
            if(now.resultt1 != 0){
                node nextt;
                nextt.id = 1; nextt.order = 3; nextt.pre = front; nextt.step = now.step+1;
                if(now.resultt1+now.resultt2 > b){
                    nextt.resultt2 = b;
                    nextt.resultt1 = now.resultt1-(b-now.resultt2);
                }else{
                    nextt.resultt2 = now.resultt1+now.resultt2;
                    nextt.resultt1 = 0;
                }
                que[rear++] = nextt;
            }
            if(now.resultt2 != b){
                node nextt;
                nextt.id = 2; nextt.order = 1; nextt.pre = front; nextt.resultt2 = b; nextt.step = now.step+1; nextt.resultt1 = now.resultt1;
                que[rear++] = nextt;
            }
            if(now.resultt2 != 0){
                node nextt;
                nextt.id = 2; nextt.order = 2; nextt.pre = front; nextt.resultt2 = 0; nextt.step = now.step+1;  nextt.resultt1 = now.resultt1;
                que[rear++] = nextt;
            }
            if(now.resultt2 != 0){
                node nextt;
                nextt.id = 2; nextt.order = 3; nextt.pre = front;   nextt.step = now.step+1;
                if(now.resultt1+now.resultt2 > a){
                    nextt.resultt1 = a;
                    nextt.resultt2 = now.resultt2-(a-now.resultt1);
                }else{
                    nextt.resultt1 = now.resultt1+now.resultt2;
                    nextt.resultt2 = 0;
                }
                que[rear++] = nextt;
            }
        front++;
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    while(Scand3(a, b, c) == 3){
        bfs();
        if(!success)
            printf("impossible\n");
    }
    return 0;
}

I題:

題意:

兩個熊孩子在n*m的平地上放火玩,#表示草,兩個熊孩子分別選一個#格子點火,火可以向上向下向左向右在有草的格子蔓延,點火的地方時間爲0,蔓延至下一格的時間依次加一。求燒完所有的草需要的最少時間。如不能燒完輸出-1。

思路:

思路很簡單,這題明顯是雙入口的bfs。先把可以燒的位置存進來,然後一個二重循環,遍歷bfs 兩個入口的位置,找出最優解就行。(這裏要比較取優的原因在於,要進行多個bfs,每一個bfs求得的是最優解,然後在這些個最優解中取優)。

代碼:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int x,y,step;
};

int n,m;
char mp[100][100];
int vis[100][100];
int ans, sum;
queue<node> que;
vector<node>  v;

int dirx[] = {1,-1,0,0};
int diry[] = {0,0,1,-1};


void bfs(int x1, int y1, int x2, int y2){
    me(vis, 0);
    ans = 0;
    while (!que.empty()) {
        que.pop();
    }
    node startt;
    startt.x = x1; startt.y = y1; startt.step = 0;
    que.push(startt);
    vis[x1][y1] = 1;
    startt.x = x2; startt.y = y2; startt.step = 0;
    que.push(startt);
    vis[x2][y2] = 1;
    while (!que.empty()) {
        node now = que.front();
        que.pop();
        int xx = now.x; int yy = now.y; int stepp = now.step;
        ans = stepp;
        //        int flag = 0;
        for(int i = 0; i < 4; ++i){
            int xxx = xx + dirx[i]; int yyy = yy + diry[i];
            if(!(0 <= xxx && xxx < n) || !(0 <= yyy && yyy < m))
                continue;
            node nextt;
            nextt.x = xxx; nextt.y = yyy; nextt.step = stepp+1;
            if(mp[xxx][yyy] == '#' && !vis[xxx][yyy]){
                que.push(nextt);
                vis[xxx][yyy] = 1;
            }
        }
    }
}

int judge(){
    fo(i, 0, n)
    fo(j, 0, m)
    if(mp[i][j] == '#' && !vis[i][j])
        return 0;
    return 1;
}

int main()
{
#ifndef ONLINE_JUDGE
     //Fin;
#endif // ONLINE_JUDGE
    int T;
    while(Scand(T) != EOF){
        for(int t = 1; t <= T; ++t){
            Scand2(n, m);
            me(mp, 0);  me(vis, 0);
            for(int i = 0; i < n; ++i)
                Scans(mp[i]);
            sum = 0;
            v.clear();
            for(int i = 0; i < n; ++i){
                for(int j = 0; j < m; ++j){
                    if(mp[i][j] == '#'){
                        sum++;
                        node temp;
                        temp.x = i; temp.y = j; temp.step = 0;
                        v.push_back(temp);
                    }
                }
            }
            int result = INF;
            for(int i=0;i<v.size();i++)
            {
                for(int j=i;j<v.size();j++)
                {
                    bfs(v[i].x,v[i].y,v[j].x,v[j].y);
                    int ok = judge();
                    if(ok)
                    {
                        result = min(result,ans);
                    }
                }
            }
            
            if(result == INF)
                result = -1;
            printf("Case %d: %d\n",t,result);
        }
    }
    return 0;
}

K題:

題意:

定義一個二維數組: 

int maze[5][5] = {

	0, 1, 0, 0, 0,

	0, 1, 0, 1, 0,

	0, 0, 0, 0, 0,

	0, 1, 1, 1, 0,

	0, 0, 0, 1, 0,

};


它表示一個迷宮,其中的1表示牆壁,0表示可以走的路,只能橫着走或豎着走,不能斜着走,要求編程序找出從左上角到右下角的最短路線。

思路:

很簡單的bfs迷宮問題,由於要打印路徑,得模擬隊列+pre標記

代碼:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) {	return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE
struct node{
	int x,y;
	int pre;
}que[100];

int mp[10][10];
int vis[10][10];
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};

int check(int x, int y){
	if(!(0 <= x && x <= 4))	return 0;
	if(!(0 <= y && y <= 4))	return 0; 
	if(mp[x][y] == 1)	return 0;
	if(vis[x][y])	return 0;
	return 1;
}

void print(int ind){
	if(que[ind].pre != -1){
		print(que[ind].pre);
		printf("(%d, %d)\n",que[ind].x,que[ind].y);
	}
}

void bfs(){
	int front = 0, rear = 0;
	que[rear].x = 0; que[rear].y = 0; que[rear].pre = -1;
	rear++;
	while(front < rear){
		node now = que[front];
		int x = now.x; int y = now.y;
		//printf("now: x:%d y:%d\n",x,y);
		if(x == 4 && y == 4){
			//printf("front:%d\n",front); 
			print(front);
			return ;
		}
		fo(i,0,4){
			if(check(x+dirx[i],y+diry[i])){
				que[rear].x = x+dirx[i];
				que[rear].y = y+diry[i];
				que[rear].pre = front;
				//printf("next: x:%d y:%d\n",que[rear].x,que[rear].y);
				rear++;
			}	
		}
		front++;
	}
}


int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	me(mp,0);	me(vis,0);
	fo(i,0,5)
		fo(j,0,5)
			cin >> mp[i][j];
	cout << "(0, 0)" << endl;
	bfs();
	return 0;
}

L題:

題意:

給你一個字符矩陣,’*‘表示沒油,’@‘表示有油,求圖中油田的個數。

思路:

其實就是求連通塊個數,直接用dfs搜一遍就行(遍歷字符數組的每一個位置,如果是'@’,油田個數加一,再dfs其連通的'@',並做上標記)

代碼:

#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 100 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n,m;
char mp[maxn][maxn];
int vis[maxn][maxn];
int cnt;

int check(int x, int y){
	if(!(0 <= x && x <= m-1))	return 0;
	if(!(0 <= y && y <= n-1))	return 0;
	if(mp[x][y] != '@' || vis[x][y])	return 0;
	return 1;
} 

void dfs(int x, int y){
	for(int i = -1; i <= 1; ++i){
		for(int j = -1; j <= 1; ++j){
			if(!i && !j)	continue;
			if(check(x+i,y+j)){
				vis[x+i][y+j] = 1;
				dfs(x+i,y+j);
			}
		}
	}
} 

int main()
{
	#ifndef ONLINE_JUDGE
		Fin;
	#endif // ONLINE_JUDGE
	while(cin >> m >> n){
		getchar();
		//printf("m:%d n:%d\n",m,n);
		if(!n && !m)	break;
		me(mp,0);
		fo(i,0,m){
			scanf("%s",mp[i]);
			//printf("i:%s\n",mp[i]);	
		}
		/*fo(i,0,m){
			fo(j,0,n)
				cout << mp[i][j];
			cout << endl; 
		}*/
		cnt = 0; me(vis,0);
		fo(i,0,m)
			fo(j,0,n){
				if(mp[i][j] == '@' && !vis[i][j]){
					//printf("i:%d j:%d\n",i,j);
					cnt++;
					vis[i][j] = 1;
					dfs(i,j);
				} 
			}
		cout << cnt << endl;
	}
	return 0;
}

M題:

題意:

只有兩個杯子,它們的容量分別是N 毫升和M 毫升 可樂的體積爲S (S<101)毫升 (正好裝滿一瓶) ,它們三個之間可以相互倒可樂 (都是沒有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。問兩個人喝能平分嗎?如果能請輸出倒可樂的最少的次數,如果不能輸出"NO"。

思路:

和H題一樣的題,只不過這裏是3個容器,所以結構體需要三個變量分別記錄三個容器剩下的可樂。這裏不需要打印,不需要模擬隊列,直接用STL中的queue就行。

代碼:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scand2(a,b)     scanf("%d%d",&a,&b)
#define Scand3(a,b,c)     scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d)     scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int a,b,c;
    int step;
    node(int aa = 0, int bb = 0, int cc = 0, int stepp = 0){
        a = aa; b = bb; c = cc; step = stepp;
    }
};

int s,n,m;
queue<node> que;
int vis[200][200][200];
int ans;

void bfs(){
    while (!que.empty()) {
        que.pop();
    }
    fo(i, 0, 100)
        fo(j, 0, 100)
            fo(k, 0, 100)
                vis[i][j][k] = 0;
    node startt(s, 0, 0, 0);
    que.push(startt);
    while (!que.empty()) {
        node now = que.front();
        que.pop();
        int a = now.a; int b = now.b; int c = now.c; int step = now.step;
        if(vis[a][b][c])    continue;
        vis[a][b][c] = 1;
//        printf("a:%d b:%d c:%d step:%d\n",a,b,c,step);
        if((!a && b == c) || (!b && a == c) || (!c && a == b)){
            ans = step;
            return;
        }
        if(a > 0){
            if(a+b > n){
                node nextt(a+b-n, n, c, step+1);
                que.push(nextt);
            }else if(a+b < n){
                node nextt(0, a+b, c, step+1);
                que.push(nextt);
            }
            
            if(a+c > m){
                node nextt(a+c-m, b, m, step+1);
                que.push(nextt);
            }else if(a+c < m){
                node nextt(0, b, a+c, step+1);
                que.push(nextt);
            }
        }
        if(b > 0){
            if(b+a > s){
                node nextt(s, b+a-s, c, step+1);
                que.push(nextt);
            }else if(b+a < s){
                node nextt(b+a, 0, c, step+1);
                que.push(nextt);
            }
            
            if(b+c > m){
                node nextt(a, b+c-m, m, step+1);
                que.push(nextt);
            }else if(b+c < m){
                node nextt(a, 0, b+c, step+1);
                que.push(nextt);
            }
        }
        if(c > 0){
            if(c+a > s){
                node nextt(s, b, c+a-s, step+1);
                que.push(nextt);
            }else if(c < s){
                node nextt(c+a, b, 0, step+1);
                que.push(nextt);
            }
            
            if(c+b > n){
                node nextt(a, n, c+b-n, step+1);
                que.push(nextt);
            }else if(c+b < n){
                node nextt(a, c+b, 0, step+1);
                que.push(nextt);
            }
        }
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    while (Scand3(s, n, m) == 3) {
        if(!s && !n && !m)  break;
        ans = 0;
        bfs();
        if(ans == 0)
            printf("NO\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

N題:

題意:

一張圖,上面有'@',兩個人約定到其中的一個'@'中見面,求兩人見面所花的最短時間。

思路:

可以求出兩個人到達每一個'@'所花的時間,用兩次bfs就行,然後對於每個'@',統計兩人花費的時間(即兩人分別所花時間相加),取最小值就行。

注意點:

bfs的終止條件是遍歷完所有的'@',所以事先要記錄圖中'@'的個數

代碼:

#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n)	   scanf("%d",&n);
#define Scans(s)	   scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

struct node{
    int x,y;
    int step;
    node(int a, int b, int c){
        x = a; y = b; step = c;
    }
};

int n,m;
char mp[250][250];
int vis1[250][250]; int vis2[250][250];
queue<node> que;
int stx1,sty1,stx2,sty2;
int cnt,num;
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};

int check(int x, int y){
    if(!(1 <= x && x <= n)) return 0;
    if(!(1 <= y && y <= m)) return 0;
    if(mp[x][y] == '#' || mp[x][y] == 'Y' || mp[x][y] == 'M')	return 0;
    return 1;
}

void bfs1(){
    num = 0;
    while(!que.empty())
        que.pop();
    node startt(stx1,sty1,0);
    vis1[stx1][sty1] = 0;
    que.push(startt);
    while(!que.empty()){
        node now = que.front();
        que.pop();
        int x = now.x; int y = now.y; int step = now.step;
        if(mp[x][y] == '@'){
            num++;
            if(num == cnt)
                return;
        }
        fo(i,0,4){
            int xx = x + dirx[i];
            int yy = y + diry[i];
            if(check(xx,yy) && !vis1[xx][yy]){
                node nextt(xx,yy,step+1);
                vis1[xx][yy] = step+1;
                que.push(nextt);
            }
        }
    }
}

void bfs2(){
    num = 0;
    while(!que.empty())
        que.pop();
    node startt(stx2,sty2,0);
    vis1[stx2][sty2] = 0;
    que.push(startt);
    while(!que.empty()){
        node now = que.front();
        que.pop();
        int x = now.x; int y = now.y; int step = now.step;
        if(mp[x][y] == '@'){
            num++;
            if(num == cnt)
                return;
        }
        fo(i,0,4){
            int xx = x + dirx[i];
            int yy = y + diry[i];
            if(check(xx,yy) && !vis2[xx][yy]){
                node nextt(xx,yy,step+1);
                vis2[xx][yy] = step+1;
                que.push(nextt);
            }
        }
    }
}

int main()
{
	while(cin >> n >> m){
        me(mp,0);	me(vis1,0); 	me(vis2,0);
        cnt = 0;
        fo(i,1,n+1){
            scanf("%s",mp[i]+1);
            fo(j,1,m+1){
                if(mp[i][j] == 'Y'){
                    stx1 = i; sty1 = j;
                }
                if(mp[i][j] == 'M'){
                    stx2 = i; sty2 = j;
                }
                if(mp[i][j] == '@')
                    cnt++;
            }
        }
        bfs1();
        bfs2();
        int ans = INF;
        fo(i,1,n+1){
            fo(j,1,m+1){
                if(mp[i][j] == '@'){
                	if(!vis1[i][j] || !vis2[i][j])
                		continue;
                    ans = min(ans,vis1[i][j]+vis2[i][j]);
                }
            }
        }
        cout << ans*11 << endl;
    }
	return 0;
}

 

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