第五章 搜索与回溯算法

1215 迷宫

#include <iostream>
using namespace std;

int k, n;
char a[105][105];	//迷宫数组 
int ha, la, hb, lb; //入口、出口 
bool vst[105][105];	//标记数组 
bool success = false;

void dfs(int x, int y) {
    
    
	//无路可走 -> 回溯 
	if (a[x][y] == '#') return;
	if (x < 0 || y < 0 || x >= n || y >= n) return;
	
	//找到出口 -> 结束 
	if (x == hb && y == lb) {
    
    
		success = true;
		return;
	}
	
	//来过这里 -> 回溯	
	if (vst[x][y]) return;
	
	//到此一游,标记 
	vst[x][y] = true;
	
	//朝四个方向搜索
	dfs(x - 1, y);
	dfs(x + 1, y);
	dfs(x, y - 1);
	dfs(x, y + 1);	
}

int main() {
    
    	
	cin >> k;
	
	while (k--) {
    
    
		cin >> n;
		for (int i = 0; i < n; i ++ ) {
    
    
			for (int j = 0; j < n; j ++ ) {
    
    
				cin >> a[i][j];
				vst[i][j] = false;
			}
		}
		cin >> ha >> la >> hb >> lb;
		
		success = false;		
		dfs(ha, la);
		
		if (success) cout << "YES" << endl;
		else cout << "NO" << endl;
	}

	return 0;
}

1216 红与黑

#include <iostream>
using namespace std;

int w, h, cnt;
char a[30][30];
bool vst[30][30];

void dfs(int x, int y) {
    
    
	if (a[x][y] == '#') return;
	if (x == 0 || y == 0 || x == h+1 || y == w+1) return;
	if (vst[x][y]) return;
	
	vst[x][y] = true;
	cnt++;
			
	dfs(x - 1, y);
	dfs(x + 1, y);
	dfs(x, y - 1);
	dfs(x, y + 1);	
}

int main() {
    
    	
	while (cin >> w >> h) {
    
    
		if (w==0 && h==0) break;
		
		int x, y;
		for (int i = 1; i <= h; i ++ ) {
    
    
			for (int j = 1; j <= w; j ++ ) {
    
    
				cin >> a[i][j];
				vst[i][j] = false;
				
				if (a[i][j] == '@') {
    
    
					x = i; y = j;
				}
			}
		}
		
		cnt = 0;
		dfs(x, y);
		cout << cnt << endl;
	}
	
	return 0;
}

1212 LETTERS

#include <iostream>
using namespace std;

int r, s, cnt, maxx;
char a[30][30];
bool vst[26];

void dfs(int x, int y) {
    
    
	if (x == 0 || y == 0 || x == r+1 || y == s+1) return;
	
	//曾经经过相同的字母 -> 回溯 
	int t = a[x][y] - 'A';
	if (vst[t]) return;
	
	//标记:已访问该字母 
	vst[t] = true;
	
	//打擂台 
	maxx = max(maxx, ++cnt);
			
	//朝四个方向搜索 
	dfs(x - 1, y);
	dfs(x + 1, y);
	dfs(x, y - 1);
	dfs(x, y + 1);	
	
	//回溯寻找下一个解。恢复之前的状态,并把计数器减 1 
	vst[t] = false;
	cnt--;
}

int main() {
    
    	
	cin >> r >> s; 
	
	for (int i = 1; i <= r; i ++ ) {
    
    
		for (int j = 1; j <= s; j ++ ) {
    
    
			cin >> a[i][j];
		}
	}
		
	dfs(1, 1);
	cout << maxx;
	
	return 0;
}

1219 马走日

#include <iostream>
#include <cstring>
using namespace std;

int t, n, m, x, y, cnt, step, maxx;
bool vst[15][15];
int dx[8] = {
    
    -2, -1, +1, +2, +2, +1, -1, -2};
int dy[8] = {
    
    +1, +2, +2, +1, -1, -2, -2, -1};

void dfs(int x, int y) {
    
    
	if (x < 0 || y < 0 || x >= n || y >= m || vst[x][y]) return;
	
	if (step == n*m) {
    
    
		cnt ++ ;
		return;
	}	
	
	vst[x][y] = true;
	step ++ ;
	
	for (int i = 0; i < 8; i ++) {
    
    
		dfs(x+dx[i], y+dy[i]);
	}
	
	step -- ;
	vst[x][y] = false;
}

int main() {
    
    
	int t;	
	cin >> t;
	
	while (t--) {
    
    
		cin >> n >> m >> x >> y;
		
		memset(vst, false, sizeof(vst));
		cnt = 0;
		
		step = 1;
		dfs(x, y);

		cout << cnt << endl;
	}	
	
	return 0;
}

1317 组合的输出

#include <iostream>
#include <cstdio>
using namespace std;

int n, r, ans[30];
bool vst[30];

void dfs(int x) {
    
    
    if (x > r) {
    
    
        for (int i = 1; i <= r; i ++ ) printf("%3d", ans[i]);
        cout << endl;
        
        return;
    }
    
    for (int i = ans[x-1]+1; i <= n; i ++ ){
    
    
        if (!vst[i]) {
    
    
            vst[i] = true;
            ans[x] = i;
            
            dfs(x + 1);
            vst[i] = false;
        }
    }    
}

int main() {
    
    
    cin >> n >> r;
     
    dfs(1);

    return 0;
}

1318 自然数的拆分

#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int n, sum, ans[N];

void dfs(int x) {
    
    
	//完成拆分 ,结束
	if (sum == n) {
    
    
		cout << n << '=' << ans[1];
		for (int i = 2; i < x; i ++) cout << '+' << ans[i];
		cout << endl;
		
		return;
	}
	
	// i 既要大于等于 1,又要大于等于第 x-1 个数 
	// i 既要小于 n,又要小于等于 n-sum 
	for (int i = max(1, ans[x-1]); i <= min(n-1, n-sum); i ++) {
    
    
		//记录第 x 个数字为 i,累加 
		ans[x] = i;
		sum += i;
		
		//搜索下一个位置上的数字 
		dfs(x + 1);
		//回溯寻找下一个解,恢复之前的状态 
		sum -= i;			
	}
}

int main() {
    
    	
	cin >> n;
	
	dfs(1);
	
	return 0;
}

1222 放苹果

#include <iostream>
using namespace std;

int t, m, n;
int cnt, sum, a[15];

void dfs(int x) {
    
    
	if (x > n) {
    
    
		if (sum == m) cnt ++ ;
		return;
	}
	
	for (int i = a[x-1]; i <= m-sum; i ++) {
    
    
		a[x] = i;
		
		sum += i;
		dfs(x + 1);
		sum -= i;
	}	
}

int main() {
    
    
	cin >> t;
	
	while (t--) {
    
    
		cin >> m >> n;
		
		sum = 0;
		cnt = 0;
		dfs(1);
		cout << cnt << endl;		
	}
	
	return 0;
}

1214 八皇后

#include <iostream>
using namespace std;

int n, b, cnt;
int col[10];	//第 1 行的皇后放在第 col[1] 列,以此类推 
bool used[10]; 	//某一列是否已有皇后

//第x行 
void dfs(int x) {
    
    
	if (x > 8) {
    
    
		cnt ++;
		if (cnt == b) {
    
    
			//输出一个皇后串 
			for (int i = 1; i <= 8; i ++ ) cout << col[i];
			cout << endl;
		}
		return;
	}
	
	//从第 1 列到第 8 列中,搜索出能够放置皇后的列 
	for (int j = 1; j <= 8; j ++ ) {
    
    
		//如果第 j 列已经有皇后了,则不能放置下一个皇后 
		if (used[j]) continue; 
		
		bool flag = true;
		for (int k = 1; k < x; k ++ ) {
    
    
			//第 x 行 j 列,和第 k 行 col[k] 列是否在同一斜线上?
			if (x+j == k+col[k] || x-j == k-col[k]) {
    
    
				flag = false;
				break; 
			}
		}
		
		//第 j 列可以放置皇后 
		if (flag) {
    
    
			col[x] = j;
			//标记:第 j 列上放置了皇后 
			used[j] = true;
			
			//搜索下一行 
			dfs(x + 1);
			
			//恢复状态 
			used[j] = false;
		}		
	}
}

int main() {
    
    
	cin >> n;
	
	while (n--) {
    
    
		cin >> b;

		cnt = 0;
		//从第一行开始搜索
		dfs(1);
	}

	return 0;
}

1217 棋盘问题

#include <iostream>
#include <cstring>
using namespace std;

int n, k;
char a[10][10];
bool used[10];
//cnt表示已经放下的棋子数量 
//ans表示已经找到的方案数量 
int ans = 0, cnt = 0;

void dfs(int x) {
    
    
	if (cnt == k) {
    
    
		ans ++ ;
		return;
	}
	
	//从第 x 行~第 n 行,第 1 列~第 n 列,寻找放置下一个棋子 
	for (int i = x; i <= n; i ++) {
    
    
		for (int j = 1; j <= n; j ++) {
    
    
			//判断第 i 行第 j 列能否放置棋子?
			if (a[i][j] == '#' && !used[j]) {
    
    
					cnt ++; 
					used[j] = true;
					
					dfs(i + 1);
					
					cnt --;
					used[j] = false;
			}
		}
	}
}

int main() {
    
    
	while (cin >> n >> k) {
    
    
		if (n == -1 && k == -1) return 0;
		
		for (int i = 1; i <= n; i ++) {
    
    
			for (int j = 1; j <= n; j ++) {
    
    
				cin >> a[i][j];
			}
		}
		
		memset(used, false, sizeof(used));
		cnt = ans = 0;
		//从第 1 行开始搜索 
		dfs(1);

		cout << ans << endl;
	}

	return 0;
}

1218 取石子游戏

#include<iostream>
using namespace std;

int a, b;

void search(int a, int b, int s) {
    
    
	if (a < b) swap(a, b);
	
	if (a/b >= 2) {
    
    
		if (s%2 == 1) cout << "win" << endl;
		else cout << "lose" << endl;
		return;
	}
	
	search(a-b, b, s+1);	
}

int main() {
    
    
	while (cin >> a >> b) {
    
    
		if (a==0 && b==0) break;
		
		search(a, b, 1);
	}
	
	return 0;	
}

单词接龙

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 30;
int n, cnt[N], len, maxx;
string w[N];
char ch; 

void dfs(int last) {
    
    
	for (int now = 1; now ≤ n; now ++) {
    
    
		if (cnt[now] == 2) continue;
		
		int t = -1;
		if (last == 0) {
    
    
			if (w[now][0] == ch) t = 0;
		}
		else {
    
    
			for (int i = w[last].size() - 1; i > 0; i --) {
    
    
				string s = w[last].substr(i);
				//如果条件满足,则 s 是相连两个单词的重合部分,t是重合部分的长度 
				if (w[now].find(s) == 0) {
    
    	
					t = w[last].size() - i;
					break;
				}
			}
		} 
		if (t == -1) continue;
		
		len += w[now].size() - t;
		maxx = max(maxx, len);
		cnt[now] ++;
		
		dfs(now);
			
		cnt[now] --;
		len -= w[now].size() - t;
	}
}

int main() {
    
    
	cin >> n;
	for (int i = 1; i ≤ n; i ++) cin >> w[i];
	cin >> ch;
	
	dfs(0);
	
	cout << maxx;

	return 0;
}

1221 分为互质组 (没使用搜索)

#include <iostream>
#include <vector>
using namespace std;

int n, x;
vector<vector<int> > group;

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

int main() {
    
    
	cin >> n;
	
	cin >> x;
	vector<int> a;
	a.push_back(x);
	group.push_back(a);

	for (int i = 2; i <= n; i ++) {
    
    
		cin >> x;
		
		bool f1 = true; 
		for (int i = 0; i < group.size(); i ++) {
    
    
			bool f2 = true;
			for (int j = 0; j < group[i].size(); j ++) {
    
    
				if (gcd(x, group[i][j]) != 1) {
    
    
					f2 = false;
					break;
				}
			}
			
			//如果和第 i 组的数字都互质,就放入第 i 组 
			if (f2) {
    
    
				group[i].push_back(x);

				f1 = false;
				break;
			}
		}

		//如果无法放到前面的任何一组中,则作为新的一组 
		if (f1) {
    
    
			a.clear();
			a.push_back(x);
			group.push_back(a);
		}		
	}

	cout << group.size();

	return 0;
}

猜你喜欢

转载自blog.csdn.net/davidliule/article/details/112557665
今日推荐