信息学奥赛-一本通-第二部分 基础算法 --> 第五章 搜索与回溯算法

1317:【例5.2】组合的输出

【题目描述】

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,...,n,从中任取r个数。

现要求你用递归的方法输出所有组合。

例如n=5,r=3,所有组合为:

1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

bool vis21;

int n;

void dfs(int b, int r) { //r 控制循环层数 b控制循环起点

if (r == 0) {

for (int i = 1; i <= n; i++)

if (visi) cout << " " << i ;

cout << endl;

return ;

};

for (int i = b; i <= n; i++) {

if (visi == 0) {

visi = 1;

dfs(i + 1, r - 1);

visi = 0;

}

}

}

int main() {

//input data

int r;

cin >> n >> r;

dfs(1, r);

return 0;

}

1318:【例5.3】自然数的拆分

【题目描述】

任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。

当n=7共14种拆分方法:

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int n;

int a100005;

int sum = 0;

void dfs(int m, int index) {

if (sum > n) return;

if (sum == n) {

cout << n << "=";

cout << a1;

for (int i = 2; i < index; i++) {

cout << "+" << ai;

}

cout << endl;

return;

}

for (int i = m; i < n; i++) {

aindex = i;

sum += i;

dfs(i, index + 1);

sum -= i;

}

}

int main() {

//input data

cin >> n;

dfs(1, 1);

return 0;

}

1212:LETTERS

【题目描述】

给出一个roe×col的大写字母矩阵,一开始的位置为左上角,你可以向上下左右四个方向移动,并且不能移向曾经经过的字母。问最多可以经过几个字母。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int n, m;

char a2525;

bool vis30;

int maxc = 0;

int _next42 = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

void dfs(int i, int j, int cnt) {

maxc = max(cnt, maxc);

for (int k = 0; k <= 3; k++) {

int x = i + _nextk0;

int y = j + _nextk1;

if (x < 0 || y < 0 || x >= n || y >= m) continue;

if (visa\[xy - 'A']) continue;

visa\[xy - 'A'] = 1;

dfs(x, y, cnt + 1);

visa\[xy - 'A'] = 0;

}

}

int main() {

//input data

cin >> n >> m;

getchar();

for (int i = 0; i < n; i++) {

cin.getline(ai, 25);

}

visa\[00 - 'A'] = 1;

maxc++;

dfs(0, 0, 1);

cout << maxc;

return 0;

}

1213:八皇后问题

【题目描述】

在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

#define N 105

int aNN, bN;

int visNN;

int s;

void dfs(int step) {

if (step == 8 + 1) {

s++;

for (int i = 1; i <= 8; i++)

asi = bi;

return;

}

for (int i = 1; i <= 8; i++) {

if (vis0i == 0 && vis1step + i == 0 && vis2step - i + 8 == 0) {

vis0i = 1;

vis1i + step = 1;

vis2step - i + 8 = 1;

bstep = i;

dfs(step + 1);

vis0i = 0;

vis1i + step = 0;

vis2step - i + 8 = 0;

}

}

}

int main() {

dfs(1);

for (int t = 1; t <= s; t++) {

printf("No. %d\n", t);

for (int i = 1; i <= 8; i++) {

for (int j = 1; j <= 8; j++) {

if (atj == i) cout << "1 ";

else cout << "0 ";

}

cout << endl;

}

}

return 0;

}

1214:八皇后

【题目描述】

会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 × 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。

对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。

给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int n = 8;

bool a99;

int _count = 0;

int b938;

void dfs(int m) {

if (m == 9) {

// printf("No. %d\n", ++_count);

_count++;

for (int i = 1; i <= n; i++) {

for (int j = 1; j <= n; j++) {

if (aji == 1) b_countj = i;

// printf("%d ", aji);

}

// printf("\n");

}

return;

}

for (int i = 1; i <= n; i++) { //第m行 第i列

bool flag = 1;

for (int j = 1; j <= n; j++) {

for (int k = 1; k <= n; k++) {

if (k == i && ajk == 1) flag = 0;

if (j - k == m - i && ajk == 1) flag = 0;

if (j + k == m + i && ajk == 1) flag = 0;

if (flag == 0) break;

}

}

if (flag) {

ami = 1;

dfs(m + 1);

ami = 0;

} else continue;

}

}

int main() {

//input data

dfs(1);

int m;

cin >> m;

while (m--) {

int k;

cin >> k;

for (int i = 1; i <= n; i++) {

printf("%d", bki);

}

printf("\n");

}

return 0;

}

1215:迷宫

【题目描述】

一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n×n的格点组成,每个格点只有22种状态,.和#,前者表示可以通行后者表示不能通行。同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。如果起点或者终点有一个不能通行(为#),则看成无法办到。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int n, k;

int _next42 = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

char a105105;

bool vis105105;

int sx, sy, ex, ey;

bool flag = 0;

void dfs(int x, int y) {

if (x == ex && y == ey) flag = 1;

for (int i = 0; i <= 3; i++) {

int nx = x + _nexti0;

int ny = y + _nexti1;

if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;

if (visnxny == 1 || anxny == '#') continue;

visnxny = 1;

dfs(nx, ny);

// visnxny = 0;

}

}

int main() {

//input data

cin >> k;

while (k--) {

cin >> n;

flag = 0;

memset(vis, 0, sizeof(vis));

for (int i = 0; i < n; i++) {

getchar();

for (int j = 0; j < n; j++) {

scanf("%c", &aij);

}

}

cin >> sx >> sy >> ex >> ey;

vissxsy = 1;

dfs(sx, sy);

if (flag) cout << "YES" << endl;

else cout << "NO" << endl;

}

return 0;

}

1216:红与黑

【题目描述】

有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int m, n;

int _next42 = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

char a105105;

//string a105;

bool vis105105;

int sx, sy;

int sum = 0;

//void print() {

// cout << "************************" << endl;

// for (int i = 0; i < n; i++) {

// for (int j = 0; j < m; j++) {

// cout << aij << " ";

// }

// cout << endl;

// }

//}

void dfs(int x, int y) {

for (int i = 0; i <= 3; i++) {

int nx = x + _nexti0;

int ny = y + _nexti1;

if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;

if (visnxny == 1 || anxny == '#') continue;

visnxny = 1;

sum++;

dfs(nx, ny);

// print();

}

}

int main() {

//input data

while (cin >> m >> n, m + n != 0) {

memset(vis, 0, sizeof(vis));

sum = 0;

for (int i = 0; i < n; i++) {

getchar();

for (int j = 0; j < m; j++) {

scanf("%c", &aij);

if (aij == '@') sx = i, sy = j;

}

}

// print();

vissxsy = 1;

sum++;

dfs(sx, sy);

cout << sum << endl;

}

return 0;

}

1217:棋盘问题

【题目描述】

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k个棋子的所有可行的摆放方案 C。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int n, k;

int sum = 0;

string a10;

bool vis10;

void dfs(int m, int row) {

for (int i = row; i < n; i++) {

for (int j = 0; j < n; j++) {

if (aij == '.' || visj == 1) continue;

visj = 1;

if (m == k) sum++;

else dfs(m + 1, i + 1);

visj = 0;

}

}

}

int main() {

//input data

while (cin >> n >> k, n != -1) {

sum = 0;

memset(vis, 0, sizeof(vis));

for (int i = 0; i < n; i++) {

cin >> ai;

// cout<<ai<<endl;

}

dfs(1, 0);

cout << sum << endl;

}

return 0;

}

1218:取石子游戏

【题目描述】

有两堆石子,两个人轮流去取。每次取的时候,只能从较多的那堆石子里取,并且取的数目必须是较少的那堆石子数目的整数倍,最后谁能够把一堆石子取空谁就算赢。

比如初始的时候两堆石子的数目是25和7。

25 7 --> 11 7 --> 4 7 --> 4 3 --> 1 3 --> 1 0

选手1取 选手2取 选手1取 选手2取 选手1取

最后选手1(先取的)获胜,在取的过程中选手2都只有唯一的一种取法。

给定初始时石子的数目,如果两个人都采取最优策略,请问先手能否获胜。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

bool check(int m, int n) {

if (m < n) swap(m, n);

if (m / n >= 2) return true;

else return !check(m - n, n);

}

int main() {

//input data

int m, n;

while (cin >> m >> n, m + n != 0) {

if (check(m, n)) cout << "win" << endl;

else cout << "lose" << endl;

}

return 0;

}

1219:马走日

【题目描述】

马在中国象棋以日字形规则移动。

请编写一段程序,给定n×m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int m, n;

bool vis1515;

int _next82 = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};

int sum = 0;

int ans = 0;

void dfs(int x, int y) {

for (int i = 0; i < 8; i++) {

int nx = x + _nexti0;

int ny = y + _nexti1;

if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;

if (visnxny == 1) continue;

visnxny = 1;

sum++;

if (sum == m * n) ans++;

else dfs(nx, ny);

sum--;

visnxny = 0;

}

}

int main() {

//input data

int k;

cin >> k;

while (k--) {

int x, y;

cin >> m >> n >> x >> y;

sum = ans = 0;

memset(vis, 0, sizeof(vis));

visxy = 1;

sum++;

dfs(x, y);

cout << ans << endl;

}

return 0;

}

1220:单词接龙

【题目描述】

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙"中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int n;

string str;

//int len = 0;

string a25;

int num25;

int maxlen = 0;

int check(string s, string e) { //返回重复的个数

int ls = min(s.size(), e.size());

for (int i = 1; i < ls; i++) {

if (s.substr(s.size() - i, s.size()) == e.substr(0, i)) return i;

}

return 0;

}

void dfs(int p, int len) {

maxlen = max(maxlen, len);

for (int i = 0; i < n; i++) {

int k = check(ap, ai);

if (numi == 0 || k == 0) continue; //单词用完 不能拼接

numi--;

dfs(i, len + ai.size() - k);

numi++;

}

}

int main() {

//input data

cin >> n;

for (int i = 0; i <= n; i++) { //read data and init

cin >> ai;

numi = 2;

}

for (int i = 0; i < n; i++) {

if (ai0 == an0) {

numi--;

dfs(i, ai.size());

numi++;

}

}

cout << maxlen;

return 0;

}

1221:分成互质组

【题目描述】

给定n个正整数,将它们分组,使得每组中任意两个数互质。至少要分成多少个组?

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int ans = 1e9;

int d15, group15;

int n;

int gcd(int a, int b) {

if (b == 0) return a;

else return gcd(b, a % b);

}

void dfs(int pos, int cnt) {

int i = 1;

for (i = 1; i <= cnt + 1; i++) { //group的标号

int j = 1;

for (j = 1; j < pos; j++) { //没有标号或者有互质组 j==pos

if (groupj == i && gcd(dj, dpos) > 1)

break;

}

if (j == pos) {

grouppos = i;

int flag = 0;

if (i > cnt) flag = 1;

if (pos == n)

ans = min(ans, cnt + flag);

else

dfs(pos + 1, cnt + flag);

}

}

}

int main() {

//input data

cin >> n;

for (int i = 1; i <= n; i++)cin >> di;

group1 = 1;

dfs(2, 1);

cout << ans;

return 0;

}

1222:放苹果

【题目描述】

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

【题目分析】

【代码实现】

#include <bits/stdc++.h>

using namespace std;

int m, n;

int ans;

int sum = 0;

int a15;

void print() {

for (int j = 1; j <= n; j++) {

cout << aj << " ";

}

cout << endl;

}

void dfs(int _m, int _n) {

for (int i = _m; i <= m; i++) { //枚举情况

if (sum + i <= m && _n <= n) { //满足条件

sum += i; //保存结果

if (_n == n && sum == m) ans++; //达到目的地

else dfs(i, _n + 1);

sum -= i; //恢复状态

}

}

}

int main() {

//input data

int t;

cin >> t;

while (t--) {

cin >> m >> n;

ans = 0;

sum = 0;

memset(a, 0, sizeof(a));

dfs(0, 1);

cout << ans << endl;

}

return 0;

}

相关推荐
L_09074 小时前
【C++】异常
开发语言·c++
Frostnova丶4 小时前
【算法笔记】数学知识
笔记·算法
liulilittle4 小时前
关于拥塞控制的几点思考
网络·c++·tcp/ip·计算机网络·信息与通信·tcp·通信
吴可可1234 小时前
AutoCAD 2016与2014二次开发关键差异
算法
雨白6 小时前
哈希:以时间换空间的算法实战
算法
QT-Neal6 小时前
C++ 编码规范
c++
啦啦啦啦啦zzzz7 小时前
数据结构:红黑树理论
数据结构·c++·红黑树
Yolo_TvT7 小时前
C++:默认构造函数
c++
San813_LDD7 小时前
[数据结构]LeetCode学习
数据结构·算法·图论