1. 程式人生 > >2018-7-11 ACM 專項刷題 dfs + bfs

2018-7-11 ACM 專項刷題 dfs + bfs

1. 遞迴:

先說一個遞迴的含義,就是在某個函式內部呼叫這個函式本身,或者說,呼叫一個與該函式完全相同的函式。

最簡單的一個遞迴的應用就是,輾轉相除法求最大公約數Gcd:

LL gcd(LL x, LL y) {
    if(x % y == 0) return y;
    else return gcd(y, x % y);
}

2. dfs(深度優先搜尋):

dfs 也有幾個很常見的應用,基礎思想也是遞迴,下面簡單說下常見的dfs應用:

(1)八皇后問題 & N皇后問題:

對應題目:HDU - 2553

八皇后問題,就是在8 * 8的棋盤上擺放八個皇后,要求這八個皇后,不同行,不同列,不同對角線, 問多少種擺法。

程式碼如下:

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>usingnamespace std;#define N 8//八皇后int ans;int col[10];//col[i]表示, 第i行的皇后放在第col[i]列void dfs(int k){if(k == N) ans++;else{for(int i =0; i < N; i++){bool flg 
=1; col[k]= i;for(int j =0; j < k; j++){//判斷第k行的皇后與第j行的皇后是否在同一列, 是否在同一對角線if(col[k]== col[j]|| k - col[k]== j - col[j]|| k + col[k]== j + col[j]){ flg =0;//同一主對角線上的元素的(行 - 列)是一個常數, 同一副對角線上的元素的(行 + 列)是一個常數break;}}if(flg) dfs(k +1);}}}int main(){ dfs(0); printf("%d\n", ans
);}

接下來是N皇后,開一個全域性的N即可,傳入一個N,為了防止超時,可以打表,程式碼如下:

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>usingnamespace std;int col[13];int N;/*void dfs(int k) {
	if(k == N) ans++;
	else {
		for(int i = 0; i < N; i++) {
			bool flg = 1;
			col[k] = i;
			for(int j = 0; j < k; j++) {
				if(col[k] == col[j] || k - col[k] == j - col[j] || k + col[k] == j + col[j]) {
					flg = 0;
					break;
				}
			}
			if(flg) dfs(k + 1);
		}
	}
}*/int ans[11]={-1,1,0,0,2,10,4,40,92,352,724};int main(){while(~scanf("%d",&N)&& N){//ans = 0;//dfs(0);
		printf("%d\n", ans[N]);}}

所謂打表,就是將 dfs 跑出的 1 ~ 10 皇后的結果存進ans陣列,在輸出ans[N]即可。

(2)全排列問題:

對應題目:HDU - 1716

先說下 1 ~ N 的全排列(字典序升序),程式碼如下:

#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<cmath>#include<algorithm>usingnamespace std;int n;bool vis[10];int ans[10];voidDfs(int x){if(x == n +1){for(int i =1; i <= n; i++) printf("%d ", ans[i]);
		printf("\n");}for(int i =1; i <= n; i++){if(!vis[i]){
			vis[i]=1;
			ans[x]= i;Dfs(x +1);
			vis[i]=0;}}}int main(){
	scanf("%d",&n);Dfs(1);return0;}

下面仿照上面的思路,寫一下傳進任意四個數,所能形成的四位數的全排列(以字典序升序),程式碼如下:

#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<cmath>#include<iostream>#include<algorithm>usingnamespace std;constint maxx =1e5+7;bool vis[10];int ans[10];int t[10];int n;bool chk[maxx];int res[maxx];int p;voidDfs(int x){if(x ==5){int tmp =0;for(int i =1; i <=4; i++){
			tmp += ans[i]* pow(10,4- i);}if(!chk[tmp]&& tmp >=1000){
			p++;
			res[p]= tmp;
			chk[tmp]=1;}}for(int i =1; i <=4; i++){if(!vis[i]){
			vis[i]=1;
			ans[x]= t[i];Dfs(x +1);
			vis[i]=0;}}}int main(){bool flg =0;int cnt =-1;while(scanf("%d %d %d %d",&t[1],&t[2],&t[3],&t[4]) != EOF){if(t[1]==0&& t[2]==0&& t[3]==0&& t[4]==0)break;
		memset(chk,0,sizeof(chk));
		memset(vis,0,sizeof(vis));
		memset(res,0,sizeof(res));
		p =0;
		sort(t +1, t +5);Dfs(1);for(int i =1; i <= p; i++) printf("%d\n", res[i]);}}

(3)連通及連通塊問題:

對應題目:HDU - 1312 、HDU - 1241 、Codeforces - 377A 、POJ - 2386

HDU - 1312 題解:

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>usingnamespace std;int n, m, ans;char str[25][25];int dx[5]={-1,0,1,0};int dy[5]={0,-1,0,1};void dfs(int x,int y){if(x <1|| x > n || y <1|| y > m)return;if(str[x][y]!='.')return;
	ans++;
	str[x][y]='#';for(int i =0; i <4; i++){int xx = x + dx[i];int yy = y + dy[i];
		dfs(xx, yy);}}int main(){while(~scanf("%d %d",&m,&n)){if(n ==0&& m ==0)break;int x, y;
		ans =0;for(int i =1; i <= n; i++){for(int j =1; j <= m; j++) scanf(" %c",&str[i][j]);}for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){if(str[i][j]=='@') x = i, y = j;}}
		str[x][y]='.';
		dfs(x, y);
		printf("%d\n", ans);}return0;}

HDU - 1241 題解:

#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>usingnamespace std;int n, m;char s[110][110];void dfs(int x,int y){if(x <1|| x > n || y <1|| y > m)return;if(s[x][y]=='*')return;
	s[x][y]='*';for(int i =-1; i <=1; i++){for(int j =-1; j <=1; j++){if(i !=0|| j !=0) dfs(x + i, y + j);}}}int main(){while(~scanf("%d %d",&n,&m)&& n && m){int ans =0;for(int i =1; i <= n; i++)for(int j =1; j <= m; j++) scanf(" %c",&s[i][j]);for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){if(s[i][j]=='@'){
					ans++;
					dfs(i, j);}}}
		printf("%d\n", ans);}}

Codeforces - 377A 題解:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int h, w, t;
char str[550][550];

void dfs(int x, int y) {
	if(x < 1 || x > h || y < 1 || y > w) return;
	if(str[x][y] != '.') return;
	str[x][y] = '!';
	int num = 0;
	for(int i = -1; i <= 1; i++) {
		for(int j = -1; j <= 1; j++) {
			if(!t) return;
			if(fabs(i) != fabs(j)) {
				dfs(x + i, y + j);
				if(str[x + i][y + j] == '.') num++;
			}
		}
	}
	if(num == 0) {
		str[x][y] = 'X';
		t--;
	}
}

int main() {
	scanf("%d %d %d", &h, &w, &t);
	for(int i = 1; i <= h; i++) {
		for(int j = 1; j <= w; j++) scanf(" %c", &str[i][j]);
	}
	for(int i = 1; i <= h; i++) {
		for(int j = 1; j <= w; j++) {
			dfs(i, j);
		}
	}
	for(int i = 1; i <= h; i++) {
		for(int j = 1; j <= w; j++) {
			if(str[i][j] == '!') str[i][j] = '.';
		}
	}
	for(int i = 1; i <= h; i++) {
		for(int j = 1; j <= w; j++) printf("%c", str[i][j]);
		printf("\n");
	}
	return 0;
} 

POJ - 2386 題解:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m;
char str[110][110];

void dfs(int x, int y) {
	if(x < 1 || x > n || y < 1 || y > m) return;
	if(str[x][y] == '.') return;
	str[x][y] = '.';
	for(int i = -1; i <= 1; i++) {
		for(int j = -1; j <= 1; j++) {
			if(i != 0 || j != 0) dfs(x + i, y + j);
		}
	}
}

int main() {
	int p = 0;
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++) scanf(" %c", &str[i][j]);
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			if(str[i][j] == 'W') {
				p++;
				dfs(i, j);
			}
		}
	}
	printf("%d\n", p);
	return 0;
}

(4)可轉化為深搜的其他應用:

對應題目:Codeforces - 96B

我不會轉化為dfs的模型,純暴力打表過的,我部落格寫過這題題解,詳見連結:

https://blog.csdn.net/ericgipsy/article/details/80164017

3. bfs(廣度優先搜尋):

(1)最短路問題:

bfs主要應用於求圖內某一點到另一點的最短路徑,模板程式碼如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 7;
const int Inf = 1 << 30;

char s[55][55];
int vis[55][55];
int dd[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int n, m;
int ans, res;

struct PP {
    int x, y, flg;
} p, q;

int Bfs(int x, int y) { //返回的是最短路徑經過的所有點的個數
    memset(vis, 0, sizeof(vis));
    queue <PP> qua;
    p.x = x, p.y = y, p.flg = 1;
    qua.push(p);
    while(!qua.empty()) {
        q = qua.front();
        qua.pop();
        if(q.x == n && q.y == m) return q.flg;
        if(!vis[q.x][q.y]) {
            vis[q.x][q.y] = 1;
            for(int i = 0; i < 4; i++) {
                int dx = q.x + dd[i][0];
                int dy = q.y + dd[i][1];
                if (dx >= 1 && dx <= n && dy >= 1 && dy <= m && s[dx][dy] != '#' && !vis[dx][dy]) {
                    PP tmp;
                    tmp.x = dx, tmp.y = dy, tmp.flg = q.flg + 1;
                    qua.push(tmp);
                }
            }
        }
    }
    return -1;
}

void Init() {
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
}

int main() {
    Init();
    cout << Bfs(1, 1) << endl;
}

由於bfs對路徑是實時更新的,所以無法儲存路徑,可以藉助dfs或者vector儲存路徑。

對應題目:Atcoder Beginner Contest 088 - D

題解:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 7;
const int Inf = 1 << 30;

char s[55][55];
int vis[55][55];
int dd[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int n, m;
int ans, res;

struct PP {
	int x, y, flg;
} p, q;

int Bfs(int x, int y) {
	memset(vis, 0, sizeof(vis));
	queue <PP> qua;
	p.x = x, p.y = y, p.flg = 1;
	qua.push(p);
	while(!qua.empty()) {
		q = qua.front();
		qua.pop();
		if(q.x == n && q.y == m) return q.flg;
		if(!vis[q.x][q.y]) {
			vis[q.x][q.y] = 1;
			for(int i = 0; i < 4; i++) {
				int dx = q.x + dd[i][0];
				int dy = q.y + dd[i][1];
				if (dx >= 1 && dx <= n && dy >= 1 && dy <= m && s[dx][dy] != '#' && !vis[dx][dy]) {
					PP tmp;
					tmp.x = dx, tmp.y = dy, tmp.flg = q.flg + 1;
					qua.push(tmp);
				}
			}
		}
	}
	return -1;
}

void Init() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
}

int main() {
	Init();
	ans = n * m;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++) if(s[i][j] == '#') ans--;
	if(s[1][1] == '#' || s[n][m] == '#') res = -1;
	else res = Bfs(1, 1);
	if(res == -1) ans = -1;
	else ans -= res;
	cout << ans << endl;
}

(2)可轉化為最短路的其他應用:

對應題目:POJ - 3278

POJ - 3278 題解:

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<queue>#include<iostream>#include<algorithm>usingnamespace std;constint maxx =1e5+7;int N, K;bool vis[2* maxx];struct PP {int ans;int dp;} p, q;queue<PP> qua;intBfs(int n,int k){
	p.ans =0, p.dp = n;
	qua.push(p);while(!qua.empty()){
		p = qua.front();
		qua.pop();if(p.dp == k)return p.ans;if(p.dp < k &&!vis[p.dp *2]){
			q.dp = p.dp *2;
			q.ans = p.ans +1;
			vis[q.dp]=1;
			qua.push(q);}if(p.dp < k &&!vis[p.dp +1]){
			q.dp = p.dp +1;
			q.ans = p.ans +1;
			vis[q.dp]=1;
			qua.push(q);}if(p.dp -1>=0&&!vis[p.dp -1]){
			q.dp = p.dp -1;
			q.ans = p.ans +1;
			vis[p.dp]=1;
			qua.push(q);}}}int main(){
	cin >> N >> K;if(N >= K) cout << N - K << endl;else cout <<Bfs(N, K)<< endl;return0;}

相關推薦

2018-7-11 ACM 專項 dfs + bfs

1. 遞迴: 先說一個遞迴的含義,就是在某個函式內部呼叫這個函式本身,或者說,呼叫一個與該函式完全相同的函式。 最簡單的一個遞迴的應用就是,輾轉相除法求最大公約數Gcd: LL gcd(LL x, LL y) {     if(x % y == 0) return y;

2018-7-19 ACM 專項 最短路

最短路三種演算法的模板: 1. 弗洛伊德: #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <stri

2018-7-9 ACM 日記

<Codeforces 977D>題意:給定一串序列,問能否讓序列形成一個順序,使得序列某一項是由它前一項乘2或者前一項整除3得來的,列印該順序。思路:一開始我的思路是這樣的,就是先找只能被3整除和只能被2整除的(即不能同時被3和2整除,即不能被6整除的數),然後

2018-7-18 ACM 日記

<Codeforces - 1009B> 題意: 給定一個只由'0'、'1'、'2' 組成的串,只能將0 1互換,1 2互換,不能將0 2互換,求形成字典序最小的的串。 思路: 因為1既可以和0換,又可以和2換,所以1的位置是自由的,即1可以挪到任意位置,

python 2018.7.11

寫入 def 掌握 修改 line rename 重命名文件 讀寫 ada 1. r例 # 路徑有兩種:# 1. 相對路徑, 相對於你當前程序所在的文件夾.(必須掌握)# ../ 返回上一層目錄# 相對的是當前程序所在的文件夾# 2. 絕對路徑. 1.從

2018-7-11

roo editor chmod nbsp 時間 操作 Edito stat style 20.1 shell腳本介紹20.2 shell腳本結構和執行20.3 date命令用法20.4 shell腳本中的變量20.1 shell腳本介紹20.2 shell腳本結構和執行開

2018年暑假ACM個人訓練9(動態規劃)解題報告

三角形 img 背包 使用 狀態 記憶化 logs ref wid A:m段最大字段和問題https://www.cnblogs.com/yinbiao/p/9314528.htmlB:m

11-1C/C++

1、對於以下程式碼: char *p=new char[100] p在棧上 new出來的在堆上 動態分配在堆中,其他的記憶體分配都在棧上進行。 2、static char a[2]={‘1’,‘2’,‘3’};說法是都正確? 錯誤 陣列越界 3、在C語言的定義和呼叫中,函式的定義不

[] dfs回溯 合集

題目: Permutations Input: [1,2,3] Output: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

2018/2/8 面試題第三天

問1.知道的網頁製作會用到的圖片格式有哪些?答:png-8,png-24,jpeg,gif,svg。但是上面的那些都不是面試官想要的最後答案。面試官希望聽到是Webp,Apng。(是否有關注新技術,新鮮

2018/7/11學習筆記

JSON 在前後端傳輸中的使用: 在JS中 .stringify()將JS物件轉換為JSON字串。 .parse()將JSON字串轉換為JS物件。 在JAVA中 JSONObject(json string)將JSON字串轉換為JSON物件 JSON

手把手教你用C++ 寫ACM自動神器(衝入HDU首頁)

少年,作為苦練ACM,通宵刷題的你 是不是想著有一天能夠榮登各大OJ榜首,俯瞰芸芸眾生,唔....要做到這件事情可是需要一定天賦的哦! 博主本身也搞過一段時間的acm,對刷題深有感觸,不信可以去看我部落格的acm題解(哈哈)。 不過,先給各位辛苦刷題的ACMer賠個不是,畢

7月18日記錄 二分答案跳石頭遊戲Getting

通過數:1   明天就要暑假程式設計集訓啦~莫名開心 今天做出了一道 二分答案題(好艱辛鴨)   1049: B13-二分-跳石頭遊戲(二分答案) 時間限制: 5 Sec  記憶體限制: 256 MB提交: 30  解決: 12[提交]

2018-10-7 Atcoder 日記

Atcoder Beginner 068 - C 題意: 有 n 個島嶼,k 條船,這 k 條船分別連線 ai 島嶼和 bi 島嶼,問能否只是用兩條船就從 島嶼1到達島嶼 n 思路: 這題我使用set處理的,當島嶼起點為1的時候,將其從島嶼1出發所能到達的所有島嶼 P

【LeetCode & 劍指offer】查詢與排序711旋轉陣列的最小數字(153. Find Minimum in Rotated Sorted Array)(系列)

【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...) 153. Find Minimum in Rotated Sorted Array Suppose an array sorted in ascending ord

2018-6-18 ACM 日記

<Codeforces 990C>題意:給n個只由 '(' 和 ')' 組成的串,問從這些串中選出兩個串,使他們括號匹配,能夠成多少個匹配串,自身和自身組合匹配也算。以題中第二個樣例說明:輸入:2 ( ) ( )輸出:4解釋:輸入的兩個串 a,b 分別是 a: (

總結——尋寶遊戲(bzoj3991 dfs序)

first 最短 更新數據 iostream begin 題解 長度 ras getchar 題目: Description 小B最近正在玩一個尋寶遊戲,這個遊戲的地圖中有N個村莊和N-1條道路,並且任何兩個村莊之間有且僅有一條路徑可達。遊戲開始時,玩家可以任意選擇一個

2017-10-7 清北沖刺班a.m

同時 .cpp play 很多 註意 names 出現的次數 char fin 測試 A 消失的數字 文件名 輸入文件 輸出文件 時間限制 空間限制del.cpp/c/pas del.in del.out 1s 512MB題目描述現在,我的手上有 n 個數字,分別是 a

2017-10-7 清北沖刺班p.m

-s 都沒有 iostream 路線 分數 dfs img 多次 單向 測試 A 同花順 文件名 輸入文件 輸出文件 時間限制 空間限制card.cpp/c/pas card.in card.out 1s 512MB題目描述所謂同花順,就是指一些撲克牌,它們花色相同,並

2017.11.11 ACM-ICPC2017亞洲區域賽(沈陽)重現賽 7/13 Rank10

數據 nbsp 需要 acm-icpc 進展 span 模擬 ron 能力 開場各自讀題 I題簽到..很快就過了.. 然後開了F..He寫了個暴力..Hong看了看找了個遞推式..餵給Huang拿JAVA寫了一下..很快就過了.. 然後發現K有很多人過..然後He就去開了K