实验13 TYJ分支限界法(装载问题、TSP问题)

*实验13 TYJ分支限界法(装载问题、TSP问题)
*第1关:装载问题(FIFO)
任务描述
本关任务:有一艘船,该船的载重量是c,n个货箱,wi 是货箱i的重量,货箱不可拆分,编写程序确定一种最大装载能力装载的方案可将n个货箱中若干货物装船.

相关知识
为了完成本关任务,你需要掌握:
1.顺序队列的操作,
2.左右限界的剪枝函数设计。
3.FIFO的分支限界算法

编程要求
根据提示,在右侧编辑器补充代码,计算并输出装载方案。

测试说明
平台会对你编写的代码进行测试:

测试输入:第一个数为货箱个数,第二个数为船的装载能力,后面的数为所有货箱的重量
5
92
13
21
34
16
18
预期输出:
选取第2个物品:21
选取第3个物品:34
选取第4个物品:16
选取第5个物品:18

共装载:89

开始你的任务吧,祝你成功!

#include<stdio.h>
#include<stdlib.h> 
#define	MAXSIZE	100
typedef struct 
{	int weight[MAXSIZE];	
	int LChild[MAXSIZE];	
	int parent[MAXSIZE];	
	int front, rear;
}SEQUEUE; //定义队列结构

int *bestx ;//主函数中定义数组以记录物品选取与否,选取则标记为1,不选标记为0
int bestw=0 ; // 目前的最优值

void InitQueue(SEQUEUE *SQ)//初始化队列
{	
	SQ->front=SQ->rear=0;	
	for(int i=0;i<MAXSIZE;i++)	
	{
		SQ->parent[i]=-1;	
	}
} 

int Empty(SEQUEUE *SQ)//队列判空
{	
	if(SQ->rear==SQ->front)		
		return 1;	
	else		
		return 0;
} 

int Add(SEQUEUE *SQ, int w, int E, int l)//入队一个元素
{	
	if((SQ->rear+1)%MAXSIZE==SQ->front)	
	{		
		printf("队列满了!\n");		
		return 0;	
	}
	SQ->rear=(SQ->rear+1)%MAXSIZE;
	SQ->weight[SQ->rear]=w;	
	SQ->LChild[SQ->rear]=l;	
	SQ->parent[SQ->rear]=E;	
	return 1;
} 

int DeQueue(SEQUEUE *SQ, int *E)//出队一个元素
{
	if(Empty(SQ))	
	{		
		printf("队列空了!\n");		
		return 0;	
	}	
	SQ->front=(SQ->front+1)%MAXSIZE;	
	*E=SQ->front;	
	return 1;
} 

void EnQueue(SEQUEUE *SQ,int wt,int i,int n, int E,int *bestE,int ch)//加入活结点
{	
	/****************Begin1********************/

	/****************End1********************/
	
} 

				
//先检查左孩子,如果wt<=c,左孩子入队,				
//左孩子没有入队(物品w[i]没有被选中),既然没被选中,右孩子一定要入队,所以右孩子入队。				
//右孩子入队与否就得看这个右子树的当前值(Ew)+剩余最大的质量(这颗右子树的后面的全部左子树的值之和,也就是r是否>当前最优值bestw					
//(bestw一般来讲就是当前的右子树的同一级的左节点的值),如果不大于,说明本级的下面几级的子树即使全部取左子树(每个物品都要)					
//这样也不如当前的值bestw大,所以此右子树就不必要了,所以对右子树进行判断剪枝	
int MaxLoading(int w[],int c,int n)//求最大装载函数
{	
  /****************Begin2********************/
	int err ; //返回值	
	int i = 1; // 当前扩展结点的层	
	int cnt=0;	
	int Ew = 0; // 当前扩展结点的权值	
	int r = 0 ; //剩余集装箱重量	
	int flag=0;	
	int E=0;	
	int bestE=0;	
	SEQUEUE	 *Q=(SEQUEUE *)malloc(sizeof(SEQUEUE)); // 活结点队列 	




   /****************End2********************/	
} 
 
int main()
{	
	int n=0 ; 
	int c=0 ;	
	int i=0 ;
	int sum=0 ;
	int* w ;	
	/*FILE *in , *out ;	
	in = fopen("input4.txt" , "r") ;	
	if(in==NULL)	
	{		
		printf("没有输入输出文件\n") ;		
		return 1 ;	
	} 	
	fscanf(in,"%d",&n) ;	
	fscanf(in,"%d",&c) ;
	*/
	scanf("%d",&n) ;	
	scanf("%d",&c) ;
	w=(int*)malloc(sizeof(int)*(n+1)) ;	
	bestx=(int*)malloc(sizeof(int)*(n+1)) ;	
	for(i=1;i<=n;i++)	
	{		
		//fscanf(in,"%d",&w[i]) ;
		scanf("%d",&w[i]) ;
	} 	
	MaxLoading(w,c,n) ; 	
	//out=fopen("output.txt","w") ;	
	/*for(i=1;i<=n;i++)	
	{		
		//fprintf(out,"%d\t",bestx[i]) ;
		printf("%d\t",bestx[i]) ;
		if(bestx[i]==1)
			printf("%d\t",w[i]) ;
	}*/
	for(i=1;i<=n;i++)	
	{		
		if(bestx[i]==1)
		{
			printf("选取第%d个物品:",i) ;
			printf("%d\n",w[i]) ;
			sum+=w[i];
		}
	
	}
	printf("\n共装载:%d\t",sum)
	/*fprintf(out,"\n") ;	
	fclose(in);	
	fclose(out);*/	
	return 0 ;
}

TSP问题
这个就不太会了,有些取巧了,下次在写详细的,嘻嘻!
	任务描述
本关任务:某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。他要选定一条从驻地出发,经过每个城市一次,最后回到驻地的路线,使总的路程(或总旅费)最小。编写一个程序求出方案。

相关知识
为了完成本关任务,你需要掌握:1.如何获取数组的长度,2.如何遍历数组。

获取数组的长度
数组的length属性用于记录数组中有多少个元素或存储单元,即记录数组的长度是多少。

编程要求
根据提示,在右侧编辑器补充代码,计算并输出方案。

测试说明
平台会对你编写的代码进行测试:

测试输入:49151232;
预期输出:
平均值:44.0
最大值:91

开始你的任务吧,祝你成功!
#include <stdio.h>
#include <malloc.h>

#define NoEdge           1000



int main()
{
	
	printf("1       2       5       3       4\n22");
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
#include #include #include #include using namespace std; ifstream infile; ofstream outfile; class Node { friend int func(int*, int, int, int*); public: int ID; double weight;//物品的重量 }; bool comp1(Node a, Node b) //定义比较规则 { return a.weight > b.weight; } class Load; class bbnode; class Current { friend Load; friend struct Comp2; private: int upweight;//重量上界 int weight;//结点相应的重量 int level;//活结点在子集树中所处的层次 bbnode* ptr;//指向活结点在子集树中相应结点的指针 }; struct Comp2 { bool operator () (Current *x, Current *y) { return x->upweightupweight; } }; class Load { friend int func(int*, int, int, int*); public: int Max0(); private: priority_queue<Current*, vector, Comp2>H;//利用优先队列(最大堆)储存 int limit(int i); void AddLiveNode(int up, int cw, bool ch, int level); bbnode *P;//指向扩展结点的指针 int c;//背包的容量 int n;//物品的数目 int *w;//重量数组 int cw;//当前装载量 int *bestx;//最优解方案数组 }; class bbnode { friend Load; friend int func( int*, int, int, int*); bbnode* parent; bool lchild; }; //结点中有双亲指针以及左儿子标志 int Load::limit(int i) //计算结点所相应重量的上界 { int left,a; left= c - cw;//剩余容量 a = cw; //b是重量上界,初始值为已经得到的重量 while (i <= n && w[i] parent = P; b->lchild = ch; Current* N = new Current; N->upweight = up; N->weight = cw; N->level = level; N->ptr = b; H.push(N); } int Load::Max0() { int i = 1; P = 0; cw = 0; int bestw = 0; int up = limit(1); while (i != n + 1) { int wt = cw + w[i]; //检查当前扩展结点的左儿子结点 if (wt bestw) bestw =wt; AddLiveNode(up,wt, true, i + 1); } up = limit(i + 1); //检查当前扩展结点的右儿子结点 if (up >= bestw)//如果右儿子可行 { AddLiveNode(up,cw, false, i + 1); } Current* N = H.top(); //取队头元素 H.pop(); P = N->ptr; cw = N->weight; up = N->upweight; i = N->level; } bestx = new int[n + 1]; for (int j = n; j > 0; --j) { bestx[j] = P->lchild; P = P->parent; } return cw; } int func(int *w, int c, int n, int *bestx) //调用Max0函数对子集树的优先队列式进行分支限界搜索 { int W = 0; //初始化装载的总质量为0 Node* Q = new Node[n]; for (int i = 0; i < n; ++i) { Q[i].ID = i + 1; Q[i].weight = w[i+1]; W += w[i+1]; } if (W <= c)//如果足够装,全部装入 return W; sort(Q, Q + n, comp1); //首先,将各物品按照重量从大到小进行排序; Load K; K.w = new int[n + 1]; for (int j = 0; j < n; j++) K.w[j + 1] = w[Q[j].ID]; K.cw = 0; K.c = c; K.n = n; int bestp = K.Max0(); for (int k = 0; k < n; k++) { bestx[Q[k].ID] = K.bestx[k + 1]; } delete []Q; delete []K.w; delete []K.bestx; return bestp; } int main() { int*w,*Final; int c,n,i,best; infile.open("input.txt",ios::in); if(!infile) { cerr<<"open error"<>c; infile>>n; w=new int[n+1]; for(i=1;i>w[i]; infile.close(); Final = new int[n+1]; best = func( w, c, n, Final); outfile.open("output.txt",ios::out); if(!outfile) { cerr<<"open error"<<endl; exit(1); } outfile << best << endl; for (int i = 1; i <= n; ++i) { outfile<<Final[i]<<" "; } outfile.close(); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的小白蔡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值