回溯法进阶练习

第1关:子集和问题

#include <iostream>
extern int s[10000];//存放s集合中每个元素
extern int x[10000];//解向量
extern int n,c;//n是输入元素个数,c是子集和
int result = 0;

using namespace std;

int dfs(int k)
{
    if(result == c) return true;
    if(k >= n) return false;
    if(result > c) return false;

    result += s[k];
    x[k] = 1;
    if(dfs(k + 1)) return true;
    x[k] = 0;
    result -= s[k];

    if(dfs(k + 1)) return true;

    return false;
}

第2关:最小长度圆排列

#include<cmath>
#include<iostream>
using namespace std;
extern double r[1000];//当前圆排列
extern double x[1000];//当前圆排列圆心横坐标
double best_r[1000];//用来记录结果
extern double minx;
extern int n;

void Compute()
{
    //找到了一个排列 且此半径排列存放在数组r中
    double low=0,high=0;
    for(int i=1;i<=n;i++)
    {   
        //算出每一个圆的左边界和右边界
        if(x[i]-r[i] < low) low = x[i]-r[i];
        if(x[i]+r[i] > high) high = x[i]+r[i]; 
    }
    if(high-low<minx)
    {
        minx=high-low;//更新最小长度
        for(int i=1;i<=n;i++) best_r[i]=r[i];//记录最小排列
    }
}
double center(int t)
{	
    double x_max=0;
	for(int j=1;j<t;j++)
    {   
        //t=1的时候 第一个圆不计算 横坐标记为0 
		double x_value=x[j]+2.0*sqrt(r[t]*r[j]);
		if(x_value>x_max) x_max=x_value;//取最大的那个计算值 
	} 
	return x_max;
}
void backtrack(int t)
{
    if(t==n+1)
    {
        //已经找到了一个排列
        Compute();
    }
    else
    {
        for(int j=t;j<=n;j++)
        {   
            //t之前的已经排列好 t位置依次与后面的交换 
            swap(r[t],r[j]);
            double center_x=center(t);//计算当前第t个位置的横坐标
			if(center_x+r[t]+r[1]<minx)
            {   
                //如果已经大于维护的最小值 则不必搜索 
				x[t]=center_x;//存入表示坐标的数组x中
				backtrack(t+1);//递归选择t+1位置 
			}
            swap(r[t],r[j]);//t选择j的情况已经结束 把他换回去 进行下一个交换 
        }
    }
}

第3关:工作分配问题

#include<iostream>
using namespace std;
extern int n;
extern int cost[21][21];//费用表
extern int x[21];//解向量
extern int ccost;//当前费用
extern int mincost;//最小费用
void backtrack(int t)
{
    if(ccost > mincost) return ;
    if(t > n) 
    {
        if(ccost < mincost) mincost = ccost;
        return ;
    }

    for(int i = 1;i <= n;i ++ )
        if(x[i])
        {
            x[i] = 0;
            ccost += cost[t][i];
            backtrack(t + 1);
            ccost -= cost[t][i];
            x[i] = 1;
        }
    
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值