走迷宫(寻找方法数)
给一个n行m列的2维的迷宫,‘S’表示迷宫额起点,‘T’表示迷宫的终点,’#‘表示不能通过的点,’.’ 表示可以通过的点。你需要从’S’出发走到’T’,每次只能上下左右走动,并且只能进入能通过的点,每个点只能通过一次。现在要求你求出有多少种通过迷宫的的方案。
输入格式
第一行输入n,m (1≤n,m≤10)表示迷宫大小。
接下来输入n行字符串表示迷宫。
输出格式
输入通过迷宫的方法数。
样例输入1
2 3
S.#
…T
样例输出1
2
样例输入2
3 3
S…
.#.
…T
样例输出2
2
代码:
#include <cmath>
#include <iostream>
using namespace std;
int x, y, m, n, ans = 0;
char map[15][15];
int flag[15][15];
int xx[8] = {0, 1, -1, 0}; /*横向位移*/
int yy[8] = {1, 0, 0, -1}; /*纵向位移*/
void dfs(int x, int y) {
if (map[x][y] == 'T') {
ans++;
return;
}
flag[x][y] = 1; /*标记(x,y)已经被访问*/
for (int i = 0; i < 4; i++) {
int tx = x + xx[i];
int ty = y + yy[i];
/*继续搜素周围可达的位置*/
if (map[tx][ty] != '#' && flag[tx][ty] != 1 && tx >= 1 && ty >= 1 && tx <= n && ty <= m) {
//注意处理边界
dfs(tx, ty);
}
}
flag[x][y] = 0; /*取消标记*/
}
int main() {
int start_x, start_y;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
char s;
cin >> s;
map[i][j] = s;
if (s == 'S') {
start_x = i;
start_y = j;
}
}
}
dfs(start_x, start_y);
/*从起点开始搜索*/
cout << ans << endl;
return 0;
}
划分块数(连通块)
小白和他的朋友周末相约去召唤师峡谷踏青。他们发现召唤师峡谷的地图是由一块一块格子组成的,有的格子上是草丛,有的是空地。草丛通过上下左右 4 个方向扩展其他草丛形成一片草地,任何一片草地中的格子都是草丛,并且所有格子之间都能通过上下左右连通。如果用’#‘代表草丛,’.'代表空地,下面的峡谷中有 2 片草地。
##…
…##
处在同一个草地的 2 个人可以相互看到,空地看不到草地里面的人。他们发现有一个朋友不见了,现在需要分头去找,每个人负责一片草地,想知道他们至少需要多少人。
Input
第一行输入 n, m (1 ≤ n,m ≤ 100) 表示峡谷大小。
接下来输入 n 行字符串表示峡谷的地形。
Output
输出至少需要多少人。
Sample Input 1
5 6
.#…
…#…
…#…#
…##.
.#…
Sample Output 1
5
代码:
#include <iostream>
using namespace std;
int book[111][111];
char map[111][111];
int ans;
int n, m;
int xd[4]{1, 0, -1, 0}, yd[4]{0, -1, 0, 1};
void dfs(int x, int y) {
book[x][y] = 1;
for (int i = 0; i < 4; i++) {
int xx = x + xd[i];
int yy = y + yd[i];
if (xx >= 0 && xx < n && yy >= 0 && yy < m && book[xx][yy] == 0 && map[xx][yy] == '#')
dfs(xx, yy);
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> map[i][j];
}
}
ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (book[i][j] == 0 && map[i][j] == '#') {
dfs(i, j);
ans++;
}
}
}
cout << ans;
}
n皇后(不冲突的方案数)
输出n皇后问题的方案数。
#include <iostream>
using namespace std;
int n;
int bookc[20], bookx[20], booky[20];
int ans = 0;
void dfs(int deep) {
if (deep == n) {
ans++;
return;
}
for (int i = 0; i < n; i++) {
if (bookx[i + deep] == 0 && booky[n + i - deep] == 0 && bookc[i] == 0) {
bookx[i + deep] = 1;
booky[n + i - deep] = 1;
bookc[i] = 1;
dfs(deep + 1);
bookx[i + deep] = 0;
booky[n + i - deep] = 0;
bookc[i] = 0;
}
}
}
int main() {
cin >> n;
dfs(0);
cout << ans;
return 0;
}
方程解
蒜头君在求解一个 n 元的高次方程:
k
1
x
1
p
1
+
.
.
.
k
n
x
n
p
n
=
0
k_1x_1^{p_1}+...k_nx_n^{p_n}=0
k1x1p1+...knxnpn=0
其中:x1 ,x2 ,…,xn 是未知数,k1, k2,…, kn 是系数,p1, p2,…, pn 是指数。方程中所有数都一定是整数。
输入格式:
第一行输入一个整数 (1≤n≤4)。
第二行输入一个整数 M (1≤M≤150)。
第 3 行到第 n+2 行,每行输入两个整数,分别表示ki (|ki| < 20), pi (1<= pi <= 4).两个整数之间用一个空格隔开。
输出格式:
输出一行,输出一个整数,表示方程的整数解的个数。
代码
#include <cstring>
#include <iostream>
#include <stdio.h>
using namespace std;
int n, M;
int k[5], p[5];
int mypow[160][5];
int ans = 0;
void init() {
memset(mypow, 1, sizeof(mypow));
for (int i = 1; i <= 150; i++)
for (int j = 1; j <= 4; j++)
mypow[i][j] = i * mypow[i][j - 1];
}
void dfs(int num, int mark) {
if (num != 0 && num != n && mark == 0)
return;
if (num == n) {
if (mark == 0)
ans++;
return;
}
for (int i = 1; i <= M; i++)
dfs(num + 1, mark + k[num] * mypow[i][p[num]]);
}
int main() {
cin >> n;
cin >> M;
init();
for (int i = 0; i < n; i++)
cin >> k[i] >> p[i];
dfs(0, 0);
cout << ans;
return 0;
}
等边三角形
蒜头君手上有一些小木棍,它们长短不一,蒜头君想用这些木棍拼出一个等边三角形,并且每根木棍都要用到。 例如,蒜头君手上有长度为1,2,3,3 的4根木棍,他可以让长度为1,2 的木棍组成一条边,另外2 跟分别组成2条边,拼成一个边长为3的等边三角形。蒜头君希望你提前告诉他能不能拼出来,免得白费功夫。
输入格式
首先输入一个整数 n(3≤n≤20),表示木棍数量,接下来输入n根木棍的长度 pi(1≤pi≤10000)。
输出格式
如果蒜头君能拼出等边三角形,输出"yes",否则输出"no"。
样例输入1
5
1 2 3 4 5
样例输出1
yes
样例输入2
4
1 1 1 1
样例输出2
no
#include <algorithm>
#include <iostream>
using namespace std;
int n;
int len[22], bian, book[22];
int flag = 0;
void dfs(int tmp, int sum, int edge) {
if (sum > bian)
return;
if (sum == bian && edge < 3)
dfs(0, 0, edge + 1);
if (sum == bian && edge == 3) {
flag = 1;
return;
}
for (int i = tmp; i < n; i++) {
if (book[i])
continue;
book[i] = 1;
dfs(i + 1, sum + len[i], edge);
book[i] = 0;
}
}
int main() {
cin >> n;
int sum = 0, Max = 0;
for (int i = 0; i < n; i++) {
cin >> len[i];
sum += len[i];
Max = max(Max, len[i]);
}
if (sum % 3 != 0 || Max > sum / 3) {
cout << "no";
return 0;
}
bian = sum / 3;
dfs(0, 0, 1);
if (flag)
cout << "yes";
else
cout << "no";
return 0;
}
数独
给一个指定的数独进行填空。
#include<stdio.h>
#include<stdlib.h>
int check(int arr[9][9], int x, int y, int t)
{
for (int i = 0; i < 9; i++)
{
if (arr[x][i] == t || arr[i][y] == t)
return 0;
}
int maze[] = { 0,3,6 };
int left = maze[x / 3];
int right = maze[y / 3];
for (int i = left; i < left + 3; i++)
{
for (int j = right; j < right + 3; j++)
{
if (arr[i][j] == t)
return 0;
}
}
return 1;
}
void dfs(int arr[9][9], int x, int y)
{
if (x == 9)//找到唯一最优解
{
for (int i = 0; i < 9; i++)//输出
{
for (int j = 0; j < 9; j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
return;
}
if (arr[x][y] == 0)
{
for (int i = 1; i <= 9; i++)//遍历合法数字填空
{
if (check(arr, x, y, i) == 1)//判断是否合法
{
arr[x][y] = i;//状态转移
dfs(arr, x + (y + 1) / 9, (y + 1) % 9);//递归下一个坐标点,即深搜
}
}
arr[x][y] = 0;//如果前面的循环都没有找到唯一的最优解,则回溯
}
else
{
dfs(arr, x + (y + 1) / 9, (y + 1) % 9);//递归搜索下一个坐标点
}
}
int main()
{
int arr[9][9] = { {0,0,5,3,0,0,0,0,0},
{8,0,0,0,0,0,0,2,0},
{0,7,0,0,1,0,5,0,0},
{4,0,0,0,0,5,3,0,0},
{0,1,0,0,7,0,0,0,6},
{0,0,3,2,0,0,0,8,0},
{0,6,0,5,0,0,0,0,9},
{0,0,4,0,0,0,0,3,0},
{0,0,0,0,0,9,7,0,0} };
dfs(arr, 0, 0);
system("pause");
return 0;
}
总结
dfs的重要组成部分有map[],book[],dx[],dy[]。由于递归的特性,很多变量最好写成全局变量。