前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >回溯算法

回溯算法

原创
作者头像
_春华秋实
发布2023-08-27 20:35:06
2080
发布2023-08-27 20:35:06
举报
文章被收录于专栏:_春华秋实_春华秋实

回溯法是一种类似于穷举的解决方式

思路:遍历所有可选择元素或者数据,如果当前选择不符合问题要求就会产生回溯,即抛弃当前的选择回到上一个状态并进行其他的选择。

装载问题

[问题描述]

有n个集装箱要装上一艘载重量为W的轮船,其中集装箱i ( 1≤i≤n )的重量为wi。不考虑集装箱的体积

限制,现要这些集装箱中选出若干装上轮船, 使它们的重量之和等于W ,当总重量相同时要求选取的集装箱个数尽可能少。

解题思路:

这个问题可以抽象成把所有的货物组合情况找最优解的场景场景,所以搬货物可以看作一个满二叉树,每一个货物都有选择 or 不选择两种情况(每一层都代表选不选择这个货物),遍历这个满二叉树得到最优解

添加描述

代码语言:javascript
复制

#include <stdio.h>
#include <string.h>   
#define MAXN 20
//全局变量 
int w[]={0,5,2,6,4,3} ;
int n=5,W=10; //船的容量和载重
int maxw=0;   //存放最优解的总重量,初值是0
int x[MAXN];  //存放最优解向量,初值是0
int minnum=999999;   //存放最优解的集装箱个数,初值为最大值

/**
num :选择的集装箱个数;
tw :  已经装载到第一艘轮船上的集装箱重量之和
rw :  剩余集装箱的重量和
op : 表示一个解,即一个选择方案,选择时,op=1,不选时,op=0
i : 表示考虑的第i个集装箱
*/
void dfs(int num,int tw,int rw,int op[],int i){
	if(i>n){  //i>n说明所有的集装箱都判断完了 
		if(tw==W&&num<minnum){ //满足这个条件即为最优解,则覆盖之前的解 
			maxw=tw;
			minnum=num;
			for(int j=1;j<=n;j++){
				x[j]=op[j];  //把最优解的值依次赋给最优解向量 
			}
		}
	}else{  //没到最后一个集装箱则需要判断当前这个集装箱是选还是不选 
		op[i]=1;  //如果选择 
		if(tw+w[i]<=W){  //判断剪枝条件 
			dfs(num+1,tw+w[i],rw-w[i],op,i+1);
		}
		op[i]=0;  //如果不选
		if(tw+rw-w[i]>=W){  //判断剪枝条件 
			dfs(num,tw,rw-w[i],op,i+1);
		} 
	}
}
	
void displaySolution(int n){
	for(int i=1;i<=n;i++){
		if(x[i]==1){
			printf("选择第%d个集装箱\n",i);
		}
	}
	printf("总重量为%d\n",maxw);
}
	
int main(){
	int op[MAXN];   //op存放所有可行解 
	int rw;
	memset(op,0,sizeof(op));  //初始化为0 
	for(int i=1;i<=n;i++){
		rw=rw+w[i];   //初始剩余量=所有集装箱饿和 
	}
	dfs(0,0,rw,op,1);  //从第一个开始
	displaySolution(n);  //输出解
	return 0; 
} 

全排列问题

代码语言:javascript
复制
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]

回溯思路:使用递归实现数组元素交换,然后输出交换后的所有字符情况

由于数组是引用变量,回溯时数组元素没有还原到未进行选择前的状态,所以加了一条语句进行还原。体现了回溯要保持和元数据相同。

代码语言:javascript
复制
// Golang 代码实现
var res [][]int
 
func permute(nums []int) [][]int {
    res = [][]int{}
    backtrack(nums, 0)
    return res
}
 
func backtrack(nums []int, idx int) {
    if idx == len(nums) {
        temp := make([]int, len(nums))
        copy(temp, nums)
        res = append(res, temp)
        return
    }
    for i := idx; i < len(nums); i++ {
        nums[i], nums[idx] = nums[idx], nums[i]
        backtrack(nums, idx+1)
        nums[i], nums[idx] = nums[idx], nums[i]
    }
}
代码语言:javascript
复制
// C 语言代码实现
#include<stdio.h>
void perm(char s[],int k,int n){
    int i;
    char tmp;
    if(k==n-1){
        for(i=0;i<n;i++)
            printf("%c",s[i]);
        printf("\n");
    }else{
        for(i=k;i<n;i++){
            if (i!=k)
                tmp = s[k];s[k] = s[i];s[i] = tmp;//交换s[k]与s[i] 
            perm(s,k+1,n);
            if (i!=k)
                tmp = s[k];s[k] = s[i];s[i] = tmp;//交换s[k]与s[i],恢复环境即回溯。 
        }
    }
}
int main(){
    int n=3;
    char s[] = "123";
    perm(s,0,n);
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 装载问题
  • 解题思路:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档