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

问题描述:

设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设是从供应商j处购得的部件i的重量,是相应的价格。试设计一个优先队列式分支限界法,给出总价格不超过d的最小重量机器设计。

[之所以想记录这个问题,是因为我觉得自己"用各个部件的最小重量作为未来最理想重量"的这个设计还挺特别。其他都是实验报告中的内容]

算法描述:

算法实现:

#include<stdio.h>
#include<stdlib.h>

struct NodeType
{
    int *mark;    //记录部件i的供应商
    int preview;    //当前已买部件重量+未来最理想重量
    int now;    //当前考虑买的部件
    int nowd;    //当前已买部件价格
    struct NodeType* next;
};

#define MAXINT 65534;
int doit(int n,int m,int d,int **w,int **c,int *future)
{
    int frist=0;
    while(frist<m&&c[0][frist]>d)
       frist++;
    //找第一个部件的不超过价格上限的供应商frist
    if(frist==m)return 0;
    //第一个部件的所有供应商的价格都超过价格上限,无法购买

    /*
    构造优先队列的第一个结点
    */
    struct NodeType *h,*t,*temp;
    h=t=temp=temp=(struct NodeType *)malloc(sizeof(struct NodeType));
    temp->mark=(int *)malloc((sizeof(int))*n);
   temp->preview=future[0]+w[0][frist];    //当前已买部件重量+未来最理想重量
    temp->now=0;        //当前考虑买的部件为部件0
   temp->nowd=c[0][frist]; //当前已买部件价格(部件0在供应商frist处购买的价格)
    temp->mark[0]=frist;    //部件0在供应商frist处购买
    temp->next=NULL;
    for(int i=frist+1;i<m;i++)
    {
        if(c[0][i]<=d)    //若在供应商i处购买部件0的价格没有超过价格上限(约束剪枝)
        {
            temp=(struct NodeType *)malloc(sizeof(struct NodeType));
            temp->mark=(int *)malloc((sizeof(int))*n);
            temp->preview=future[0]+w[0][i];//当前已买部件重量+未来最理想重量
            temp->now=0;   //当前考虑买的部件为部件0
            temp->nowd=c[0][i]; //当前已买部件价格(部件0在供应商i处购买的价格)
            temp->mark[0]=i;    //部件0在供应商i处购买
            temp->next=NULL;
            t->next=temp;
            t=t->next;
        }
    }
    int realmin=MAXINT;    //记录最小重量
    int *markmin;
    markmin=(int *)malloc((sizeof(int))*n);
  //记录部件i的供应商markmin[i]
    struct NodeType *minr,*minp,*r,*q;
    while(h!=NULL)
    {
    /*
    找到队列中重量最小的结点作为扩展结点(minp)
    */
        int min=realmin;//-
         r=q=h;
        while(q!=NULL)
        {
            if(q->preview<min)
            {
                min=q->preview;
                minr=r;
                minp=q;
            }
            r=q;
            q=q->next;
        }
        for(int i=0;i<m;i++)
        {
            if(minp->nowd+c[minp->now+1][i]<=d)
            //若已买部件价格加上在供应商i处购买
       //部件minp->now+1的价格小于等于价格上限
            {
                temp=(struct NodeType *)malloc(sizeof(struct NodeType));
                temp->mark=(int *)malloc((sizeof(int))*n);
            /*
            当前已买部件重量+未来最理想重量
            */
                temp->preview=0;
                for(int j=0;j<(minp->now+1);j++)
                    temp->preview+=w[j][minp->mark[j]];
          //先计入之前已买的部件的重量
                temp->preview+=w[minp->now+1][i];
          //在计入当期在供应商i处购买部件minp->now+1的重量
                temp->preview+=future[minp->now+1];
          //最后计入未来最理想的重量
                temp->now=minp->now+1;              //当前考虑买的部件为部件minp->now+1

                temp->nowd=minp->nowd+c[minp->now+1][i];
           //当前之前已买部件价格+在供应商i处购买部件
          //minp->now+1的价格
            /*
            记录之前已买部件的供应商+当前部件的供应商i
            */
                for(int j=0;j<(minp->now+1);j++)
                    temp->mark[j]=minp->mark[j];
                temp->mark[minp->now+1]=i;
                temp->next=NULL;

                if(temp->now+1==n&&temp->preview<realmin)
          //若当前考虑的部件已经是最后一个部件,
          //且在供应商i处购买这个部件,
                //能够使得现在部件总重量优于当前求解出的最优值
                {

                /*记录最优值和最优解*/
                        realmin=temp->preview;
                        for(int j=0;j<n;j++)markmin[j]=temp->mark[j];
                        free(temp);
                }
                else
                {
                //若当前考虑的部件并非最后一个部件,将此结点加入队列
                    t->next=temp;
                    t=t->next;
                }
            }
        }
        if(minp==h)//拓展结点为头结点
        {
            h=h->next;
            free(minp);//将拓展结点释放
        }
        else    //拓展结点非头结点
        {
            minr->next=minp->next;
            free(minp);//将拓展结点释放
        }
    /*
    如果当前队列中的结点的最理想重量大于已经求出的最优解,则将该结点释放
    */
        while(h->preview>=realmin&&h!=t)
        {
            q=h;
            h=h->next;
            free(q);
        }
        if(h->preview>=realmin)
        {
            free(h);
            h=NULL;
        }
    }
    /*
    输出最优值及最优解
    */
    printf("%d\n",realmin);
    for(int i=0;i<n;i++)printf("%d ",markmin[i]+1);
    return 0;
}
int main()
{
    int n,m,d;
    scanf("%d %d %d",&n,&m,&d);//部件数,供应商数,价格上限
    int ** c;
    c=(int **)malloc((sizeof(int *))*n);
    for(int i=0;i<m;i++)
       c[i]=(int *)malloc((sizeof(int))*m);
    for(int i=0;i<n;i++)
       for(int j=0;j<m;j++)
          scanf("%d",&c[i][j]);
    //在供应商j处购买部件i的价格c[i][j]
    int ** w;
    w=(int **)malloc((sizeof(int *))*n);
    for(int i=0;i<m;i++)
       w[i]=(int *)malloc((sizeof(int))*m);
    for(int i=0;i<n;i++)
       for(int j=0;j<m;j++)
          scanf("%d",&w[i][j]);
    //在供应商j处购买部件i的重量w[i][j]
    int * future;
    future=(int *)malloc((sizeof(int))*n);
    for(int i=0;i<n;i++)
    {
        int min=MAXINT;
        for(int j=0;j<m;j++ )
           if(min>w[i][j]) min=w[i][j];
        future[i]=min;
    }
    for(int i=0;i<n-1;i++)
    {
       future[i]=0;
       for(int j=i+1;j<n;j++)
         future[i]+=future[j];
    }
    future[n-1]=0;
    //购买完部件i后剩余部件的最理想重量
    doit(n,m,d,w,c,future);
    //优先队列分支限界算法
    return 0;
}

原文地址:https://www.cnblogs.com/kk980414/p/9787041.html

时间: 2024-10-29 07:46:21

优先队列式分支限界法-最小重量机器设计问题的相关文章

RQNOJ 622 最小重量机器设计问题:dp

题目链接:https://www.rqnoj.cn/problem/622 题意: 一个机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得. w[i][j]是从供应商j处购得的部件i的重量,c[i][j] 是相应的价格. 试设计一个算法,给出总价格不超过d的最小重量机器设计. 题解: 表示状态: dp[i][j] = min weight i:考虑到第i个零件 j:当前花费 找出答案: min dp[n][j] (0<=j<=d) 如何转移: 对于当前零件i,枚举不同的供应商j,转移

最小重量机器设计问题

1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,d; 4 int array1[100][100]; 5 int array2[100][100]; 6 int cw=0; 7 int cp=0; 8 int bestw=1000000; 9 int x[100]; 10 int x1[100]; 11 void machine(int t){ 12 if(t>=n){ 13 if(cw<bestw){ 14 b

用优先队列式分支限界法解决0-1背包问题

用优先队列式分支限界法解决0-1背包问题的算法思想: 1.分支限界法常以广度优先或最小耗费优先(最大效益优先)方式搜索问题的解空间树, 对于0-1背包问题的解空间树是一个颗子集树. 2.在分支限界法中有一个活结点表,活结点表中的每个活结点只有一次机会成为扩展结点,一旦成为  扩展结点就一次性产生所有儿子结点,在这些儿子结点中,导致不可行解或导致非最优解的儿子 结点被舍弃,其余儿子结点被加入到活结点表中.对于0-1背包问题中的每个活结点只有两个儿子 结点,分别表示对物品i的选取和对物品i的舍去:在

最小重量机器问题

/*最小重量机器问题*/ #include<stdio.h> int w[100][100]; //w[i][j]为第i个零件在第j个供应商的重量 int c[100][100]; //c[i][j]为第i个零件在第j个供应商的价格 int bestx[100]; //bestx[i]表示一次搜索到底后的最优解,用来存放第i个零件的供应商, int x[100]; //x[i]临时存放第i个零件的供应商 int cw=0,cc=0,bestw=10000; int cost; //限定价格 i

最小重量问题的分支界限法的C++实现方案

*1.问题描述:* *2.解题思路* 这个题目基本思想是 利用分支界限法, 核心就是需要设计一个 优先级标准, 这里我们将 问题的层数,也就是第i个部件作为优先级, 对于相同i的部件,以重量更小的作为优先级的评价标准,然后借助标准库中的优先级队列实现,分支界限法 查找目标. 另外需要注意的是, 使用标准库中的优先级队列时候需要自己重载operator< ,而且一定要有const,233333333 3.源代码 3.1MinMachine.h #pragma once #include <que

从Storm和Spark Streaming学习流式实时分布式计算系统的设计要点

0. 背景 最近我在做流式实时分布式计算系统的架构设计,而正好又要参见CSDN博文大赛的决赛.本来想就写Spark源码分析的文章吧.但是又想毕竟是决赛,要拿出一些自己的干货出来,仅仅是源码分析貌似分量不够.因此,我将最近一直在做的系统架构的思路整理出来,形成此文.为什么要参考Storm和Spark,因为没有参照效果可能不会太好,尤其是对于Storm和Spark由了解的同学来说,可能通过对比,更能体会到每个具体实现背后的意义. 本文对流式系统出现的背景,特点,数据HA,服务HA,节点间和计算逻辑间

HTML5----响应式(自适应)网页设计

现在,很多项目都需要做响应式或者自适应的来适应我们不同屏幕尺寸的手机,电脑等设备,那么就需要我们在页面上下功夫,下面我就来说一下如何做响应式(自适应)的网页设计 1.在网页代码的头部,加入一行viewport元标签 <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">

自动构造词法分析器的步骤——正规式转换为最小化DFA

3p渤采刂9味7J1PF四刚http://www.zcool.com.cn/collection/ZMTkwNDQ0MzY=.html d4刀9瓷RHX1秩http://www.zcool.com.cn/collection/ZMTkwNDQ0ODg=.html 6u未猎7贺97S9持OEUhttp://www.zcool.com.cn/collection/ZMTkwNDQ1MTI=.html 8Y绽兆懈B婆3S7YO糜http://www.zcool.com.cn/collection/ZM

分支界限法 | 装载问题(先入先出队列式分支限界法)

输入要求 有多组数据.每组数据包含2行.第一行包含2个整数 C(1 <= C <= 1000).和 n(1 <= n <= 10),分别表示的轮船的载重量和集装箱的个数.第二行包含n个整数,依次表示n个集装箱的重量w.(0 <= w <= 1000) 输出要求 对于每组输入数据,按出队次序输出每个结点的信息,包括所在层数,编号,已装载重链,轮船上集装箱的个数每个结点的信息占一行,如果是叶子结点且其所代表的装上轮船的集装箱的个数大于当前最优值(初始为0),则输出当前最优值