第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;
}
}