回溯法

11 篇文章 0 订阅
10 篇文章 0 订阅

回溯法

一般思路:

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值