回溯法
一般思路:
void func(层数){
if(满足结束条件){
输出;
}
else{
for i in 当前层数可行解{
func(层数+1);
}
}
}
子集树
该类问题一般解是一个集合的子集,这种可以用0-1编码的二叉树解决,层数为总集合个数。如求某个集合的某个子集和为某个值的问题。
子集和问题
描述
给定一个整数集合和一个数C,寻求一个子集合,使得元素和为C。
思路
每个元素选或不选,即0、1,是一个二叉树,层数为原集合中元素个数。
可以考虑先排个序,这样在选某一层的可行解时,如果遇到和大于C的情况,后面的值都不用考虑了。
代码
#include <vector>
#include <iostream>、
#include <algorithm>
using namespace std;
int n = 5;
vector<int> vec(n,0);
vector<int> val = {1,2,4,7,3};
int C = 10;
int res = 0;
int cal_pre(int n)//下标前n值(共n+1个)的和
{
int sum = 0;
for (int i = 0; i <= n; i++)
sum += val[i] * vec[i];
return sum;
}
void place(int k)
{
if (k == n)
return;
int sum = cal_pre(k - 1);//计算前k个值的和
if (sum + val[k] > C)
return;
if (sum + val[k] == C) {
for (int i = 0; i < k; i++) {
if (vec[i] == 1)
cout << val[i]<<" ";
}
cout << val[k] << endl;;
res++;
}
if (sum + val[k] < C) {
vec[k] = 0;
place(k + 1);
vec[k] = 1;
place(k + 1);
}
}
int main()
{
sort(val.begin(), val.end());//升序排列,不然解<1,2,3,4>会被忽略
place(0);
cout << res;
system("pause");
return 0;
}
排列树
一般解是某一个序列的一个排列,如4皇后问题就是对1 2 3 4 进行重排列;哈密顿回路是对顶点顺序进行重排列。
n皇后问题
代码
#include "stdafx.h"
#include <vector>
#include <iostream>
using namespace std;
int n = 8;
vector<int> vec(n,0);
int res = 0;//解个数
void place(int k)
{
if (k == n){
for (auto i : vec){
cout << i << " ";
}
cout << endl;
res ++;
return;
}
for (int i = 0; i < n; i++) {
int j = 0;
for (; j < k; j++) {
if (vec[j] == i || (vec[j] - i) == (j - k) || (vec[j] - i) == (k - j))//如果当前改值与之前的列数有重复或者在同一斜线上,则改值不可作为当行的值。
break;
}
if (j == k){
vec[k] = i;
place(k + 1);
}
}
}
int main()
{
place(0);
cout << res;
system("pause");
return 0;
}
哈密顿回路
#include <vector>
#include <iostream>、
#include <algorithm>
#include <queue>
using namespace std;
int n = 5;
vector<bool> visited(n, false);
vector<int> res;
int level = 0;
int vec[5][5] = {0,1,0,1,0,
0,0,1,0,0,
0,0,0,0,1,
1,0,1,0,0,
0,0,0,1,0};
void hamilton(int k)
{
if (level == n - 1) {//判断终止,注意这里不是 k == n-1
if (vec[k][0])
for (auto i : res)
cout << i << " ";
return;
}
for (int i = 1; i < n; i++) {
if (vec[k][i] && !visited[i]) {
visited[i] = true;
res.push_back(i);
level++;
hamilton(i);
level--;
visited[i] = false;
res.pop_back();
}
}
}
int main()
{
visited[0] = true;
res.push_back(0);
hamilton(0);
system("pause");
return 0;
}

1万+

被折叠的 条评论
为什么被折叠?



