递归回溯法算法框架[一]
int Search(int k)
{
for (i=1;i<=算符种数;i++)
if (满足条件)
{
保存结果
if (到目的地) 输出解;
else Search(k+1);
恢复:保存结果之前的状态{回溯一步}
}
}
递归回溯法算法框架[二]
int Search(int k)
{
if (到目的地) 输出解;
else
for (i=1;i<=算符种数;i++)
if (满足条件)
{
保存结果;
Search(k+1);
恢复:保存结果之前的状态{回溯一步}
}
}
例题:
1.CODE[VS] 1294 全排列
题目描述 Description
给出一个n, 请输出n的所有全排列
输入描述 Input Description
读入仅一个整数n (1<=n<=10)
输出描述 Output Description
一共n!行,每行n个用空格隔开的数,表示n的一个全排列。并且按全排列的字典序输出。
样例输入 Sample Input
3
样例输出 Sample Output
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
#include<iostream>
#include<cstdio>
using namespace std;
int n,num[12];
bool pd[12];
void dfs(int x)
{
if (x == n)
{
for(int i = 1; i <= n; i ++)
printf("%d ",num[i]);
printf("\n");
return;
}
for(int i = 1; i <= n ; i ++)
{
if(!pd[i])
{
pd[i] = 1;
num[x + 1] = i;
dfs(x + 1);
pd[i] = 0;
}
}
}
int main()
{
scanf("%d",&n);
dfs(0);
return 0;
}
2.CODE[VS]1116 四色问题
题目描述 Description
给定N(小于等于8)个点的地图,以及地图上各点的相邻关系,请输出用4种颜色将地图涂色的所有方案数(要求相邻两点不能涂成相同的颜色)
数据中0代表不相邻,1代表相邻
输入描述 Input Description
第一行一个整数n,代表地图上有n个点
接下来n行,每行n个整数,每个整数是0或者1。第i行第j列的值代表了第i个点和第j个点之间是相邻的还是不相邻,相邻就是1,不相邻就是0.
我们保证a[i][j] = a[j][i] (a[i,j] = a[j,i])
输出描述 Output Description
染色的方案数
样例输入 Sample Input
8
0 0 0 1 0 0 1 0
0 0 0 0 0 1 0 1
0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0
1 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
样例输出 Sample Output
15552
数据范围及提示 Data Size & Hint
n<=8
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int map[10][10],n,clr[100],ans=0;
void dfs(int x)
{
if(x > n)
{
ans ++;
return;
}
for(int i = 1; i <= 4 ; i ++)//四种颜色
{
bool key = 0;//判断相邻点的颜色
for(int j = 1;j <= n; j ++)
{
if(map[x][j] == 1 && i == clr[j])//如果当前点与j相邻且颜色相同
{
key = 1;
break;
}
}
if(key) continue;
if(!key)//回溯 在开始进行重新染色
{
key = 1;
clr[x] = i;
dfs(x + 1);
clr[x] = 0;
}
}
}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n; i ++)
for(int j = 1;j <= n; j ++)
scanf("%d",&map[i][j]);
dfs(1);
cout << ans;
return 0;
}
3.CODE[VS]1295 N皇后问题
题目描述 Description
在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上。
输入描述 Input Description
给定棋盘的大小n (n ≤ 13)
输出描述 Output Description
输出整数表示有多少种放置方法。
样例输入 Sample Input
8
样例输出 Sample Output
92
数据范围及提示 Data Size & Hint
n<=13
本题显然每行只能有一个皇后 所以保证每个皇后不被攻击只需要判断每一列上即两条对角线上的情况即可
#include<iostream>
#include<cstdio>
using namespace std;
int n,ans = 0,num[15];
bool b[30] = {0}, c[30] = {0}, d[30] = {0};
//b 为列 c(横纵坐标纸和相同)从右上到左下 d(横纵坐标之差相同)是从左上到右下
void dfs(int x)
{
for(int i = 0;i < n; i ++)//逐行搜素 x为行 i为列
{
if(!b[i] && !c[x + i] && !d[x - i + n - 1])//+n防止数组出现负数
{
num[x] = i;
b[i] = 1;
c[x + i] = 1;
d[x - i + n - 1] = 1;
if(x == n)
{
ans ++;
}
else
dfs(x + 1);
b[i] = 0;
c[x + i] = 0;
d[x - i + n - 1] = 0;
}
}
return;
}
int main()
{
scanf("%d",&n);
dfs(1);
cout << ans << endl;
return 0;
}