最小重量机器设计问题-分支限界法(优先队列分支限界法)

问题描述:

 设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设是从供应商j处购得的部件i的重量,是相应的价格。

 试设计一个优先队列式分支限界法,给出总价格不超过d的最小重量机器设计。


代码

#include<iostream>
#include<queue>


using namespace std;


int n;    //部件数量
int m;    //供应商数量
int d;    //价格上限
int bestw;   //最小的重量
int **c  = NULL;    //二维数组,每个部件不同商家的价格
int **w = NULL;     //二维数组,每个部件不同商家的重量


//每一个部件的信息
class Node
{
public:
   int weight;        //当前已选机器的重量和
   int val;           //当前已选机器的价值和
   int source;        //哪个供货商
   int level;         //第几层,也代表了第几个部件
   int priority;      //优先级
   Node *father;
};

Node *leaf;//叶子结点

void InPut(){
    cout<<"请分别输入部件个数,供应商个数,及最大的总价格(n m d):"<<endl;
   cin>>n>>m>>d;
   w = new int*[n+1];
   c = new int *[n+1];
   for(int i = 1;i <= n ; i ++)
   {
       w[i]  = new int [m+1];
       c[i] = new int [m+1];
   }
   leaf = NULL;

   cout<<"请输入各个部件在各个供应商处购买的价格:"<<endl;
   for(int i = 1 ; i <= n ; i ++)
       for (int j = 1 ; j <= m ; j ++)
           cin>>c[i][j];
   cout<<"请输入各个部件在各个供应商处购买的重量:"<<endl;
   for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++)
           cin>>w[i][j];

}


//优化的优先级设定
bool operator<(Node a,Node b)  //level按照减序
{
   if(a.priority == b.priority)return a.level <b.level;  //如果重量相同,选择level大的。
   return a.priority > b.priority;//否则,重量小的先出队
}


//计算当前节点的优先级
void QueuePriority(Node a)
{
	int currentMinW;

	a.priority =a.val;
       //int temp_min_c = INT_MAX;
	 for(int i=a.level+1 ; i<=n ; i++)//选出剩余的部件在售货商中购买的最小质量,就是选择每一层最小的质量
    {
        currentMinW= INT_MAX;
        for(int j=1;j<=m;j++)  //每一层找最小的
        {
            currentMinW = currentMinW<w[i][j]?currentMinW:w[i][j];//从m个商家中选择当层重量最小的
        }

        a.priority+=currentMinW;
    }

}

//约束函数
bool constraint(Node* pNode,int i){
    if(pNode->val+c[pNode->level +1][i] <=d ||pNode->weight  +w[pNode->level +1][i] <= bestw){
        return true;
    }
    return false;
}


//创建节点
Node createNode(int level,Node* father,int source,int val,int weight){
    Node newNode;
    newNode.level = level;//层次加1
    newNode.father = father;
    newNode.source = source;
    newNode.val =val ;
    newNode.weight = weight;
    return newNode;
}



void MinWeightMachine()
{
   int i,j;
   bestw = INT_MAX;

   Node initial;
   initial=createNode(0,NULL,0,0,0);
   QueuePriority(initial);      //计算优先级
   priority_queue<Node> heap;   //用优先队列,建立一个最小堆。加入进去就会自动排好序的。
   heap.push(initial);


   while(!heap.empty())
   {
       Node *pNode = new Node(heap.top());
       heap.pop();//队首元素作为父节点出队,即优先级值小的活结点先扩展
       if(pNode->level == n)//到达叶节点,不能扩展 ,得到一个解
       {
           if(pNode->weight <bestw)   //更新
           {
               bestw = pNode -> weight;
               //MinValue  = pNode ->val;
               leaf = pNode;   //记录是最后是哪个结点数据,便于回溯找最优解
           }
       }
       else
       {
           for(i=1;i<=m;i++)//扩展结点,依次选择每个售货商,每次都是m叉树
           {
               //可行性剪枝和限界剪枝
               if(constraint(pNode,i))
               {
                   Node newNode;//生儿子结点
                   newNode=createNode(pNode->level +1,pNode,i,pNode->val + c[pNode->level +1][i],pNode->weight + w[pNode->level +1][i]);
                   QueuePriority(newNode);     //计算优先值
                   heap.push(newNode);//儿子入队

               }
           }
       }
   }

}



void OutPut(){
    cout<<"求得的最小重量为:"<<bestw<<endl;
   int *result = new int[n+1];
   for(int i=n;i>=1;i--)
   {
       result[i] = leaf ->source;//从最后叶子结点回溯到根节点
       leaf = leaf ->father;
   }
   cout<<"各个部件的供应商分别为:"<<endl;
   for(int i=1;i<=n;i++)
       cout<<result[i]<<" ";
   cout<<endl;
}

int main()
{
   InPut();
   MinWeightMachine();
   OutPut();

}



测试样例

输入
请分别输入,部件个数,供应商个数,及最大的总价格:
3 3 4
请依次输入各个部件在各个供应商处购买的价格:
1 2 3
3 2 1
2 2 2
请依次输入各个部件在各个供应商处购买的重量:
1 2 3
3 2 1
2 2 2

输出
求得的最小重量为:4
各个部件的供应商分别为:
1 3 1

在这里插入图片描述

  • 11
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
TSP问题是指旅行商问题,即在给定的一些城市中,旅行商要找到一条路径,使得他可以从一个城市出,经过所有城市,最后回到起点,并且要求路径的总长度最小分支限界法是一种解决TSP问题的有效方法,其中优先队列分支限界法是其中的一种实现方式。 优先队列分支限界法将活结点表按照某个估值函数C(x)的值组织成一个优先队列,并按优先队列中规定的结点优先级选取优先级最高的下一个结点成为当前扩展结点。在TSP问题中,每个节点表示一个城市,记录了从树的根节点(即起始点)出到该城市的一条路径。使用优先队列来存储节点,节点的优先级为该条路径最终费用的下界,这个下界为当前费用加上还没有经过的点的最小出边费用之和。在更新一个节点后,如果现只差一个点就能够遍历全部点时,该节点的费用加上到达最后一个点的费用,再加上最后一个点到初始节点的费用,就是路径总费用,可以尝试更新最优解。当从优先级队列中取出的节点为叶子节点时,就找到了最优解。 下面是使用Python实现优先队列分支限界法求解TSP问题的代码示例: ```python import heapq def tsp(graph, start): n = len(graph) visited = set([start]) heap = [(0, start, visited)] while heap: (cost, node, visited) = heapq.heappop(heap) if len(visited) == n: return cost + graph[node][start] for neighbor, distance in enumerate(graph[node]): if neighbor not in visited: new_cost = cost + distance new_visited = visited | set([neighbor]) lower_bound = new_cost + min(graph[neighbor]) * (n - len(new_visited)) heapq.heappush(heap, (lower_bound, neighbor, new_visited)) # 示例 graph = [[0, 2, 9, 10], [1, 0, 6, 4], [15, 7, 0, 8], [6, 3, 12, 0]] start = 0 print(tsp(graph, start)) # 输出:21 ```
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值