算法设计与分析实验

贪心算法

贪心算法总是做出在当前看来事最好的选择。也就是说,贪心算法并不从整体最优上加以考虑,所做的选择只是在某种意义上的局部最优选择。
注:贪心算法不是对所有问题都能得到整体最优解,但对许多问题产生整体最优解,比如最小生成树问题、图的单源最短路径问题等

贪心算法和动态规划的差异

动态规划算法中,每步所做的选择往往依赖于相关子问题的解。因而只有解出相关子问题后,才嫩做出选择。
贪心算法中,仅在当前状态下做出最好的选择,即局部最优选择。再去解做出这个选择后产生的相应的子问题。贪心算法所做的贪心选择可以依赖以往所做过的选择,但决不依赖将来所作的选择,也不依赖子问题的解。
正式上述差别,动态规划算法通常以自底向上的方式解各子问题,贪心算法则通常以自顶向下的方式进行。
具体的差异,通过经典的背包问题阐述,看问题2.

1. 活动安排问题

设有n个活动的集合E={1,2,....,n},其中每个活动都要求使用同一资源,如演讲场会等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有要求使用该资源的起始时间\(s_{i}\)和结束时间\(f_{i}\),且\(s_{i}<f_{i}\)
活动i和活动j相容=时间错开=当\(s_{i}\ge f_{j}或s_{j}\ge f_{j}\)
活动安排问题,就要要在所给的活动集合中选出最大的相容活动子集合。

//先对活动按结束时间飞递减排序
void GreedySelector(int n,Type s[],Type f[],bool A[])
{
  A[1]=true;
  int j=1;
  for(int i=2;i<=n;i++)  
  {
    if(s[i]>=f[j])//检查之后的活动与A中活动的相容性。
    {//相容,则纳入A中
      A[i]=true;
      j=i;
    }
    else//不相容,则不纳入
      A[i]=false;
  }
}

算法示例:

选择贪心算法的意义:使剩余的可安排时间段极大化,以便安排尽可能多的相容活动。

具体实践代码:

#include<iostream>
#define max 101
using namespace std;
/*
11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14
*/



int n;
float s[max],f[max];
bool A[max];
struct T
{
	float s;
	float f;
};
T* t;
void swap(T* t1,T*t2)
{
	T temp=*t1;
	*t1=*t2;
	*t2=temp;
}
void sorted(T* t,int n)
{
	for(int i=0;i<n-1;i++)
		for(int j=0;j<n-i-1;j++)
		{
			if(t[j].f>t[j+1].f)
				swap(t[j],t[j+1]);
		}
}
void GreedySelector(int n,T* t,bool A[max])
{
	A[0]=true;
	int j=0;
	for(int i=1;i<n;i++)
	{
		if(t[i].s>=t[j].f) 
		{
			A[i]=true;
			j=i;
		}
		else
			A[i]=false;
	}
}

int main()
{	t=new T[max]; 
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>t[i].s>>t[i].f;
		A[i]=false;
	} 
	sorted(t,n);
	cout<<"排序后:"<<endl;
	for(int j=0;j<n;j++)
		cout<<t[j].s<<" "<<t[j].f<<endl; 
	GreedySelector(n,t,A);
	for(int j=0;j<n;j++)
	{
		if(A[j])
			cout<<"活动:"<<j+1; 
	 } 
	
	return 0;
	
}

2 背包问题与01背包问题

0-1背包问题:给定n种物品和一个背包。物品i的重量是\(w_{i}\),其价值为\(v_{i}\),背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?
在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也能只装入部分的物品i。
形式化表述:\(给定c>0,w_{i}>0,v_{i}>0 (1\leq i\leq n),要求找出一个n元的0-1向量(x_{1},x_{2},...,x_{n}),x_{i}\in \{0,1\},1\leq i\leq n,使得\sum_{i=1}^n w_{i}x_{i}\leq c,而且\sum_{i=1}^n v_{i}x_{i}达到最大\)

背包问题:与0-1背包问题相似,不同的是在选择物品\(i(1\leq i\leq n)\)装入背包式,可以选择物品i的一部分,而不一定要全部装入背包。
形式化表述:\(给定c>0,w_{i}>0,v_{i}>0 (1\leq i\leq n),要求找出一个n元向量(x_{1},x_{2},...,x_{n}),x_{i}\in \{0,1\},0\leq x_{i}\leq 1,1\leq i\leq n,使得\sum_{i=1}^n w_{i}x_{i}\leq c,而且\sum_{i=1}^n v_{i}x_{i}达到最大\)

背包问题可以用贪心算法求解,但0-1背包问题不能用贪心算法求解
背包问题的贪心算法描述

void Knapsack(int n,float M,float v[],float w[],float x[])
{
  Sort(n,v,w);//按单位重量价值降序排列
  int i;
  for(i=1;i<=n;i++)
    x[i]=0;
  float c=M;//c为背包容量
  for(i=1;i<=n;i++)  //如果当前物品重量小于背包容量,则将物品装入,更新背包容量为除去当前物品的重量。
  {
     if(w[i]>c)
        break;
     x[i]=1;
     c-=w[i];
  }
  if(i<=n)  //当物品没装满,统计背包容量能还能装多少。
    x[i]=c/w[i];
}

3. 背包问题:

算法思想:
基于贪心算法的背包问题是可以得到最优解的。其算法思想是先按单位价值对物品进行排序,优先选择单位价值最高的物品进行装入,直至背包容量满载。

执行结果:

实现代码:

#include <iostream>
#define Max 20
using namespace std;

struct T
{
	float v;
	float w;
	float pval;
 };

T* t;
int n;
float W;
float x[Max];


void swap(T* t1,T* t2)
{
	T temp=*t1;
	*t1=*t2;
	*t2=temp;
}

void Sort()
{
	for(int i=0;i<n-1;i++)
		for(int j=0;j<n-i-1;j++)
		{
			if(t[i].pval<t[i+1].pval)
			{
				swap(t[i],t[i+1]);
			}
		}
}

void knapsack()
{
	Sort();
	int i;
	for(i=0;i<n;i++)
	{
		x[i]=0;	
	}	
	
	float c=W;
	for(i=0;i<n;i++)
	{
		if(t[i].w>c)
			break;
		x[i]=1;
		c=c-t[i].w;
	}
	if(i<=n)
		x[i]=c/t[i].w;
} 

void output()
{
	for(int i=0;i<n;i++)
	{
		cout<<t[i].v<<endl;
		cout<<t[i].w<<endl;
		cout<<t[i].pval<<endl;
	}
}

int main()
{
	t=new T[Max];
	n=3;
	//初始化物品权重和价值 
	W=50;
	t[0].v=60;
	t[0].w=10;
	t[0].pval=t[0].v/t[0].w;
	
	t[1].v=100;
	t[1].w=20;
	t[1].pval=t[1].v/t[1].w;
	
	t[2].v=120;
	t[2].w=30;
	t[2].pval=t[2].v/t[2].w;
//	output();
//	Sort();
//	cout<<"Sorted:"<<endl; 
//	output();
	knapsack();
	for(int i=0;i<n;i++)
		cout<<x[i]<<" "<<t[i].w<<endl;
	
}

回溯法

1.子集和问题

问题:

>———————————————————————————————————————————

参考:

具体分析:


#include<iostream>
using namespace std;
#define max 1000

int n,c; //元素数,目标和
int csum,r;//当前和,剩余和
int x[max]={0};//元素数组
int w[max];//s数值数组

bool backtrack(int i)
{
	//终止:到叶节点
	if(i>=n)
	{
		if(csum==c) return true;
		else return false;
	}	
	r-=w[i];//除去i后的剩余和
	//约束左分支:当前和大于目标和,左分支可剪 
	if(csum+w[i]<=c)
	{
		x[i]=1;
		csum+=w[i];
		//判断左分支是否有解 
		if(backtrack(i+1))
			return true;

        //else return false;   这地方写false就不进入右分支了

  		csum-=w[i];
	} 
	//约束右分支:当前和加剩余和(不包括w[i])是否大于目标和,
	//是,则分支;不是,则剪枝(因为没意义)
	if(csum+r>=c)
	{
		x[i]=0;
		if(backtrack(i+1))
			return true;
	} 
	r+=w[i];
	return false; 
} 
 int main(){
 	cin>>n>>c;
 	int i;
 	for(i=0;i<n;i++){
 		cin>>w[i];
 		r+=w[i];
 	}
 	if(backtrack(0))
 	{
 		int j;
 		for(j=0;j<n;j++)
 			if(x[j]==1)
 				cout<<w[j]<<" ";
	 }
	 else
	 	cout<<"No Solution!"<<endl;
	return 0;
 }

问题:

  1. r(剩余和)在进入左右分支前后要更新和回复。(模板之一)
  2. 这是有返回的backtrack,所以跟无返回的有点差别,差别在返回,无返回的遇到某个解后会继续往后探索;
  3. 还有return false问题,左分支内你想写return false,那你右分支不进行了?。

2.幂集问题

问题:

———————————————————————————————————————————

参考:

具体分析:


#include<iostream>
using namespace std;
#define Max 255
int n;//元素个数
int w[Max];
int x[Max];//元素数组

int count=0;//子集个数

void backtrack(int i)
{
    //终止
    if(i>n)
    {
        count++;//!!或者加return;就不用写else
    }else{//!!这里的else加了,当到叶节点就不往后执行了。
    	w[i]=1;
    	backtrack(i+1);
    	w[i]=0;
    	backtrack(i+1);
	}
}
int main()
{
    int i;
    cin>>n;
    for(i=0;i<n;i++)//输入元素 
    {   
		cin>>x[i];
     }
    backtrack(1);//为什么从1开始,画个图就知道了 
    cout<<count<<endl;
    return 0;
}

问题:

  1. 想着套子集和的框架,这个只需遍历所有结果就行。不用考虑剪枝。
  2. 返回的问题(是否用else)
    不加else,到叶节点了,也会继续递归,会造成错误。
    要么加else,终止了就不执行else代码块;要么不加else,但if里加return;

3. 01背包问题

问题:

———————————————————————————————————————————

参考:

具体分析:


#include <iostream>
#include <algorithm>
using namespace std;
 
struct T//!结构体!
{
    double weight;
    double value;
    double devide;
};
 
int n;
double c; //n件物品和背包容量c
double sum = 0, sumval = 0, bestval = 0; //sum:当前重量 sumval:当前价值 bestval:最大价值
T* t; //!结构体!
 
bool cmp(T t1, T t2)
{
    return t1.devide > t2.devide; 
}
 
int Bound(int y) //约束函数
{
    int i = y;
    double leftv = 0; 
    double leftw = c - sum;
    while (i < n && t[i].weight <= leftw) 
    {
        leftw -= t[i].weight;
        leftv += t[i].value;
        i++;
    }
    if (i < n) //背包装满 
    {
        leftv += t[i].devide*leftw;
    }
    return leftv;
}
 
void Backtrack(int i)
{
    if (i >= n) //递归终止条件
    {
        if (sumval > bestval)
        {
            bestval = sumval;
        }
        return;
    }
    if (sum + t[i].weight <= c)
    {
        sum += t[i].weight;
        sumval += t[i].value;
        Backtrack(i + 1);
        
        sumval -= t[i].value; 
        sum -= t[i].weight;
    }
	//通过边界,剪枝 
    if (sumval + Bound(i + 1) > bestval)
    {
        Backtrack(i + 1);
    }
}
 
int main()
{
    cin >> n >> c;
    t = new T[n];
    for (int i = 0; i <n; i++)//!结构体!
    {
        cin >> t[i].weight >> t[i].value;
        t[i].devide = t[i].value / t[i].weight;
    }
    sort(t, t+n, cmp); //剪枝优化,采取价值高的优先 
    Backtrack(0);
    cout << bestval;
    return 0;
}

问题:上面代码是最终通过的代码,不是早期错误版本。

  1. 耗时过多:无结构体版本,套用了子集和的框架,但耗时无法压下来。
    想通过:优化剪枝(bound函数);排序(优先选取价值高的);来降低耗时
  2. 对C++的结构体不太清楚,直接借鉴了参考的代码。
  3. 注意Backtrack函数的参数从0还是从1开始;通过随便一个案例画图就可得知
    从0开始,则终止条件为:i>=n
    从1开始,则终止条件为:i>n

3.1 输出分析版


具体策略:

利用回溯=递归+剪枝,有选择的遍历解,从而获取特定解。
递归每个解的时候,利用剪枝策略:
左剪枝策略是当前和(不包括当前节点重量)+当前节点重量是否大于背包容量,当大于背包容量时,则说明左分支之后的解都是大于背包容量,可以不遍历;当小于或等于背包容量时,则说明左分支存在解。
右剪枝策略是计算,右分支能达到的最大背包价值是否大于当前最优背包价值,如果大于则说明右分支有解,如果小于则剪枝。

————————————————————

#include <iostream>
#include <algorithm>
using namespace std;
 
struct T
{
    double weight;
    double value;
    double devide;
};

int n;
double c; //n件物品和背包容量c
double sum = 0, sumval = 0, bestval = 0; //sum:当前重量 sumval:当前价值 bestval:最大价值
T* t; 
 
void swap(T *i,T *j){
	T temp=*i;
	*i=*j;
	*j=temp;
}
void sort(T *t)
{
 int i;
 for (i = 0; i < n-1; i++) //
    {
        for (int j = 0; j < n-i-1; j++) //从0开始一直到len-i-1的是这次需要确认最大值数量
            if (t[j].value < t[j+1].value)
            {
				swap(t[j],t[j+1]);
            }
	}	
}

int Bound(int y) //约束函数
{
    int i = y;
    double leftv = 0; 
    double leftw = c - sum;
    while (i < n && t[i].weight <= leftw) 
    {
        leftw -= t[i].weight;
        leftv += t[i].value;
        i++;
    }
    if (i < n) //背包装满 
    {
        leftv += t[i].devide*leftw;
    }
    return leftv;
}
 
void Backtrack(int i)
{	cout<<"当前结点"<<t[i].weight<<"\n";
    if (i >= n) //递归终止条件
    {	cout<<"判断叶子"<<endl; 
        if (sumval > bestval)
        {	cout<<"判断最优"<<endl; 
            bestval = sumval;
        }
        return;
    }
   
    cout<<"进入"<<t[i].weight<<"左分支"<<endl; 
    if (sum + t[i].weight <= c)
    {
        sum += t[i].weight;
        sumval += t[i].value;
        Backtrack(i + 1);
        
        sumval -= t[i].value; 
        sum -= t[i].weight;
    }
    cout<<"进入"<<t[i].weight<<"右分支"<<endl; 
	//通过边界,剪枝 
	double bound=Bound(i+1);
	
//	cout<<"bound="<<sumval+bound<<"  bestval="<<bestval<<"\n"; 
    if (sumval + bound > bestval)
    {	
        Backtrack(i + 1);
    }
    cout<<"结束"<<t[i].weight<<endl;
}
 
int main()
{	
    cin >> n >> c;
    t = new T[n+1];
    for (int i = 0; i <n; i++)
    {
        cin >> t[i].weight >> t[i].value;
        t[i].devide = t[i].value / t[i].weight;
    }
   
    sort(t); //剪枝优化,采取价值高的优先 
     cout<<"排序后:"; 
    for(int i=0;i<n;i++)
	{
		cout<<t[i].weight<<" "<<t[i].value<<"\n";
	
	}
    Backtrack(0);
    cout << bestval;
    return 0;
}

4 最优装载问题

问题:

使用回溯法求解最优装载问题:集装箱数量n=3,两艘轮船的载重量C1=C2=70, 每个集装箱的重量W={20,50,30},其解空间由长度为3的0-1向量组成。请:(1)画出解空间树;(2)说明其搜索策略;(3) 给出详细求解过程;(4)给出最终的装载方案

——————————————————————————

参考

递归+剪枝策略;
左剪枝:当前节点重量+之前节点总重量是否大于C1,大于则剪枝;右剪枝:之前节点总重量加剩余节点重量(针对C1)是否小于C1最优重量,小于则剪枝;

#include <iostream>
using namespace std;
#define Max 101

int n,c1,c2;//集装箱数量,最大重量 
int w[Max]={0};//重量数组 
int a[Max];//方向数组  
int tw=0;//当前重量和 
int bestw=0;// 第一个集装箱最优承重 
int r=0;//货物总重 
void Backtrack(int i)
{	//终止条件 
	if(i>=n)
	{	cout<<"判断叶子"<<endl; 
		if(tw>bestw)
		{
			cout<<"判断最优:"<<bestw<<"<"<<tw<<"?"<<endl; 
			bestw=tw;
		}
		return;
	}

	cout<<"进入"<<w[i]<<"左分支"<<endl;
    //左剪枝,当前总重量+当前节点重量是否小于等于C1船容量,是则进入,不是则剪枝
	if(tw+w[i]<=c1) 
	{
		a[i]=1;
		tw+=w[i];
		Backtrack(i+1);
		tw-=w[i];
	}
	
	cout<<"进入"<<w[i]<<"右分支" <<endl;
    //右剪枝:当前总重量+剩余总重量是否大于最优总重量,大于等于则说明可能有解,小于等于则剪枝;
	if(tw+(c1-tw)>=bestw) //最大容量是C1,得考虑这个问题
	{
		a[i]=0;
		Backtrack(i+1);		
	}
	cout<<"结束"<<w[i]<<endl; 
}


int main()
{	cin>>n>>c1>>c2;
	for(int i=0;i<n;i++)
	{
		cin>>w[i];
		r+=w[i]; 
	}
	Backtrack(0);
	cout<<bestw<<endl; 
	cout<<"C1船:"<<bestw<<" C2船:"<<r-bestw<<endl; 

	return 0;
}

分支限界法

1.背包问题

FIFO队列求解背包问题

解空间

解空间(剪枝)

运行结果

//采用队列式分枝限界法求解0/1背包问题的算法
#include <stdio.h>
#include <queue>
using namespace std;
#define MAXN 20						//最多可能物品数
//问题表示
int n=3,W=32;
int w[]={0,17,16,16};				//重量,下标0不用
int v[]={0,45,25,25};  				//价值,下标0不用
//求解结果表示
int maxv=-9999;						//存放最大价值,初始为最小值
int bestx[MAXN];					//存放最优解,全局变量
int total=1;						//解空间中结点数累计,全局变量
struct NodeType						//队列中的结点类型
{	int no;							//结点编号
	int i;							//当前结点在搜索空间中的层次
	int w;							//当前结点的总重量
	int v;							//当前结点的总价值
	int x[MAXN];					//当前结点包含的解向量
	double ub;						//上界
};
void bound(NodeType &e)			//计算分枝结点e的上界
{
	int i=e.i+1;
	int sumw=e.w;
	double sumv=e.v;
	while ((sumw+w[i]<=W) && i<=n) //超重结束 || 遍历到头
	{	sumw+=w[i];				//计算背包已装入载重
		sumv+=v[i];				//计算背包已装入价值
		i++;
	}
	if (i<=n)
		e.ub=sumv+(W-sumw)*v[i]/w[i];
	else
		e.ub=sumv;
}

void output(NodeType e)
{
    printf("no=%d,i=%d,w=%d,v=%d,ub=%.1f \n",e.no,e.i,e.w,e.v,e.ub);
}

void EnQueue(NodeType e,queue<NodeType> &qu)	//结点e进队qu
{
	if (e.i==n)					//到达叶子结点
	{
		if (e.v>maxv)			//找到更大价值的解
		{
			maxv=e.v;
			for (int j=1;j<=n;j++)	//更新最优解向量
				bestx[j]=e.x[j];

        }

        printf(":\n  X=[");	//输出最优解
	for(int i=1;i<=n;i++)
		printf("%2d",e.x[i]);		//输出所求X[n]数组
	printf("],装入总价值为%d\n",e.v);
	}
	else {
	     printf("入队:");
	    output(e);
	    qu.push(e);
	    }			//非叶子结点进队
}
void bfs()							//求0/1背包的最优解
{
	int j;
	NodeType e,e1,e2;				//定义3个结点
	queue<NodeType> qu;				//定义一个队列
	e.i=0;							//根结点置初值,其层次计为0
	e.w=0; 
	e.v=0;
	e.no=total++;
	for (j=1;j<=n;j++) //当前节点的解向量初始化
		e.x[j]=0;
	bound(e);							//求根结点的上界

	//
   printf("入队:");
	output(e); 						//输出节点的状态
	qu.push(e);						//根结点进队
	while (!qu.empty())				//队不空循环
	{
		e=qu.front(); 				//保留首节点
		qu.pop();					//出队结点e
		printf("出队:");
		output(e);//输出节点状态
		
		if (e.w+w[e.i+1]<=W)		//剪枝:检查左孩子结点
		{
			e1.no=total++;
			e1.i=e.i+1;				//建立左孩子结点
			e1.w=e.w+w[e1.i];
			e1.v=e.v+v[e1.i];
			for (j=1;j<=n;j++)		//复制解向量
				e1.x[j]=e.x[j];
			e1.x[e1.i]=1;
			bound(e1);				//求左孩子结点的上界
			EnQueue(e1,qu);			//左孩子结点进队操作
		}
		e2.no=total++;				//建立右孩子结点
		e2.i=e.i+1;
		e2.w=e.w; 
		e2.v=e.v;
		for (j=1;j<=n;j++)			//复制解向量
			e2.x[j]=e.x[j];
		e2.x[e2.i]=0;
		bound(e2);					//求右孩子结点的上界
		if (e2.ub>maxv)    
        {//若右孩子结点可行,则进队,否则被剪枝
//			printf("maxv=%d \n",maxv);
			EnQueue(e2,qu);
                
		}
	}
}
int main()
{
	bfs();					//调用队列式分枝限界法求0/1背包问题
	printf("分枝限界法求解0/1背包问题:\n  X=[");	//输出最优解
	for(int i=1;i<=n;i++)
		printf("%2d",bestx[i]);		//输出所求X[n]数组
	printf("],装入总价值为%d\n",maxv);
	return 0;
}

最优装载

优先队列求解最优装载

#include <stdio.h>
#include <queue>
#include <iostream>
using namespace std;
#define Max 20

int n=3,c1=50,c2=50;
int sumw=90;
int w[]={0,10,40,40};
int bestw=-1;
int bestx[Max];
int total=1;
struct NodeType
{
	int no;
	int i;
	int w;
	int x[Max];
	double ub;
	bool operator<(const NodeType &s) const	//重载<关系函数
	{
		return ub<s.ub;				//ub越大越优先出队
	}
};
void bound(NodeType &e)
{
	int i=e.i+1;
	int sumw=e.w;
	while((sumw+w[i]<=c1)&&i<=n)
	{
		sumw+=w[i];
		i++; 
	}
	e.ub=sumw;
}

void EnQueue(NodeType e,priority_queue<NodeType> &qu)
{
	if(e.i==n)
	{
		if(e.w>bestw)
		{
			bestw=e.w;
			for(int i=1;i<=n;i++)
				bestx[i]=e.x[i]; 
		}
		cout<<"到底"<<endl; 
//		for(int i=1;i<=n;i++)
//		{
//			cout<<e.x[i]<<endl; 
//		}
	}
	else
	{
		qu.push(e);
	}
}
 
 void bfs()
 {
 	
 	int j;
 	NodeType e,e1,e2;
 	priority_queue<NodeType> qu;
 	e.i=0;
 	e.w=0;
 	e.no=total++;
 	for(j=1;j<=n;j++)
 		e.x[j]=0;
 	bound(e);
 	cout<<e.no<<"入队:";
	qu.push(e);
	while(!qu.empty())
	{
		e=qu.top();
		qu.pop();
		cout<<e.no<<"出队:";
		if(e.w+w[e.i+1]<=c1)
		{
			e1.no=total++;
			e1.i=e.i+1;
			e1.w=e.w+w[e1.i];
			for(j=1;j<=n;j++)
			{
				e1.x[j]=e.x[j];
			}
			e1.x[e1.i]=1;
			bound(e1);
			cout<<e1.no<<"入队";
			EnQueue(e1,qu);
		 } 
		 e2.no=total++;
		 e2.i=e.i+1;
		 e2.w=e.w;
		 for(j=1;j<=n;j++)
		 	e2.x[j]=e.x[j];
		 e2.x[e2.i]=0;
		 if(e2.ub>bestw)
		 {
		 	cout<<e2.no<<"入队";
		 	EnQueue(e2,qu);
		 }
		
	 } 
	 

 }
 
 int main()
{
	bfs();
	printf("分枝限界法求解最优装载:\n  X=[");
	for(int i=1;i<=n;i++)				//输出最优解
		printf("%2d ",bestx[i]);			//输出所求X[n]数组
	printf("],\nc1装载总重量为%d\nc2装载总重量%d",bestw,(sumw-bestw));
	return 0;
}
posted @ 2023-11-16 09:35  AlexanderOscar  阅读(25)  评论(0编辑  收藏  举报