算法笔记6——回溯算法

一、定义

在这里插入图片描述

基本思想

在这里插入图片描述
在这里插入图片描述

子集树与排列树

在这里插入图片描述

//形参t为树的深度,根为1
void backtrack (int t)
{
  if (t>n) update(x);
  else
    for (int i=t; i<=n; i++)
    {
      //为了保证排列中每个元素不同,通过交换 来实现
      swap(x[t], x[i]);
      if (constraint(t) && bound(t)) backtrack(t+1);
      swap(x[t], x[i]);    //恢复状态
    }
}

二、装载问题

在这里插入图片描述

代码实现:
#define NUM 100
int n;          //集装箱的数量
int c;          //轮船的载重量
int w[NUM];       //集装箱的重量数组
int x[NUM];        //当前搜索的解向量
int r;          //剩余集装箱的重量
int cw;         //当前轮船的载重量
int bestw;         //当前最优载重量
int bestx[NUM];     //当前最优解

//形参表示搜索第t层结点
void Backtrack(int t)
{
  //到达叶子结点
  if(t>n)
  { 
    //更新最优解
    if(cw>bestw)
    {
      for(int i=1; i<=n; i++) 
        bestx[i] = x[i];
      bestw = cw;
    }
    return;
  }
//更新剩余集装箱的重量
  r -= w[t];
  //搜索左子树
  if(cw+w[t]<=c)
  {
    x[t] = 1;
    cw += w[t];
    Backtrack(t+1);
    cw -= w[t];
  }
  //搜索右子树
  if(cw+r>bestw)
  {
    x[t]=0;
    Backtrack(t+1);
  }
  r += w[t];  //恢复状态
}

r = 0;
for(int i=1;i<=n;i++)
{
	scanf("%d", &w[i]);
	r += w[i];
} 

三、0-1背包问题

在这里插入图片描述
在这里插入图片描述

代码实现:
#define NUM 100
int c;				//背包的容量
int n;				//物品的数量
int cw;				//当前重量
int cv;				//当前价值
int bestv;			//当前最优价值
//描述每个物品的数据结构
struct Object{
	int w;			//物品的重量
	int v;			//物品的价值
	double d;		//物品的单位重量价值比
}Q[NUM];			//物品的数组
//对物品以单位重量价值比递减排序的因子是:
bool cmp(Object a, Object b)
{
	if(a.d>=b.d) return true;
	else return false;
}
//物品的单位重量价值比是在输入数据时计算的:
for(int i=0; i<n; i++)
{
	scanf("%d%d",&Q[i].w,&Q[i].v);
	Q[i].d = 1.0*Q[i].v/Q[i].w;
}
//使用C++标准模板库的排序函数sort()排序:
sort(Q, Q+n, cmp);
//形参i是回溯的深度,从0开始
void backtrack(int i)
{
  //到达叶子结点时,更新最优值
  if (i+1>n) {bestv = cv; return;}
  //进入左子树搜索
  if (cw+Q[i].w<=c)
  {
    cw += Q[i].w;
    cv += Q[i].v;
    backtrack(i+1);
    cw -= Q[i].w;
    cv -= Q[i].v;
  }
  //进入右子树搜索
  if (Bound(i+1)>bestv) backtrack(i+1);
}
//形参i是回溯的深度
int Bound(int i)
{
  int cleft = c-cw;   //背包剩余的容量
  int b = cv;      //上界
  //尽量装满背包
  while (i<n && Q[i].w<=cleft)
  {
    cleft -= Q[i].w;
    b += Q[i].v;
    i++;
  }
  //剩余的部分空间也装满
  if (i<n) b += 1.0*cleft*Q[i].v/Q[i].w;
  return b;
}

四、N皇后

在这里插入图片描述
在这里插入图片描述

代码实现:
#include<bits/stdc++.h>
using namespace std;
#define NUM 20
int n;
int x[NUM];
int sum;
bool Place(int t)
{
    int i;
    for (i=1; i<t; i++)
    {
        if ((abs(t-i) == abs(x[i]-x[t]))||(x[i] == x[t]))
        return false;
    }
    return true;
}
void Backtrack(int t)
{
    int i;
    if (t>n)
    {
        sum++;
        for (i=1;i<=n;i++)
        {
            cout<<x[i]<<" ";
            cout<<endl;
        }
    }
    else{
        for (i=1; i<=n; i++)
        {
            x[t] = i;
            if (Place(t)!=0) Backtrack(t+1);
        }
        }
}
int main()
{
    while (cin>>n)
    {
        sum = 0;
        Backtrack(1);
        cout<<"Total="<<sum<<endl;

    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值