zoukankan      html  css  js  c++  java
  • 洛谷P1064 金明的预算方案(01背包)

    题目描述

    金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NNN元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

    主件 附件

    电脑 打印机,扫描仪

    书柜 图书

    书桌 台灯,文具

    工作椅 无

    如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有000个、111个或222个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的NNN元。于是,他把每件物品规定了一个重要度,分为555等:用整数1−51-515表示,第555等最重要。他还从因特网上查到了每件物品的价格(都是101010元的整数倍)。他希望在不超过NNN元(可以等于NNN元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

    设第jjj件物品的价格为v[j]v_[j]v[j],重要度为w[j]w_[j]w[j],共选中了kkk件物品,编号依次为j1,j2,…,jkj_1,j_2,…,j_kj1,j2,,jk,则所求的总和为:

    v[j1]×w[j1]+v[j2]×w[j2]+…+v[jk]×w[jk]v_[j_1] imes w_[j_1]+v_[j_2] imes w_[j_2]+ …+v_[j_k] imes w_[j_k]v[j1]×w[j1]+v[j2]×w[j2]++v[jk]×w[jk]。

    请你帮助金明设计一个满足要求的购物单。

    输入格式

    111行,为两个正整数,用一个空格隔开:

    NmN mNm (其中N(<32000)N(<32000)N(<32000)表示总钱数,m(<60)m(<60)m(<60)为希望购买物品的个数。) 从第222行到第m+1m+1m+1行,第jjj行给出了编号为j−1j-1j1的物品的基本数据,每行有333个非负整数

    vpqv p qvpq (其中vvv表示该物品的价格(v<10000v<10000v<10000),p表示该物品的重要度(1−51-515),qqq表示该物品是主件还是附件。如果q=0q=0q=0,表示该物品为主件,如果q>0q>0q>0,表示该物品为附件,qqq是所属主件的编号)

    输出格式

    一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000<200000<200000)。

    输入输出样例

    输入 #1 
    1000 5
    800 2 0
    400 5 1
    300 5 1
    400 3 0
    500 2 0
    
    输出 #1 
    2200
    魔改01背包,思路是把选附件的情况和选主件合并到一起考虑而非单独考虑,一共只有五种情况。
    #include <bits/stdc++.h>
    using namespace std;
    int n,m;
    int dp[32005]={0};
    int cost[65][3]={0};//价值,0为主,1,2为附件 
    int val[65][3]={0};//重要度 
    int tot[65][3]={0};//重要度*价值 
    int main()
    {
        cin>>n>>m;
        int i;
        for(i=1;i<=m;i++)
        {
            int v,p,q;
            cin>>v>>p>>q;
            if(!q)
            {
                cost[i][0]=v;
                val[i][0]=p;
                tot[i][0]=p*v; 
            }
            else if(!cost[q][1])//第一个附件
            {
                cost[q][1]=v;
                val[q][1]=p;
                tot[q][1]=p*v;
            } 
            else
            {
                cost[q][2]=v;
                val[q][2]=p;
                tot[q][2]=p*v;
            }
        }
        for(i=1;i<=m;i++)
        {
            if(!cost[i][0])continue;//非主件跳过(虽然说不加也没有任何影响,因为一个max保证了当i为附件时的0一定不会被考虑进去 
            int j;
            for(j=n;j>=1;j--)
            {
                if(j>=cost[i][0])dp[j]=max(dp[j],dp[j-cost[i][0]]+tot[i][0]);//不选和只选主件 
                if(j>=cost[i][0]+cost[i][1])dp[j]=max(dp[j],dp[j-cost[i][0]-cost[i][1]]+tot[i][0]+tot[i][1]);//选主件和第一件 
                if(j>=cost[i][0]+cost[i][2])dp[j]=max(dp[j],dp[j-cost[i][0]-cost[i][2]]+tot[i][0]+tot[i][2]);//主件和第二件 
                if(j>=cost[i][0]+cost[i][1]+cost[i][2])dp[j]=max(dp[j],dp[j-cost[i][0]-cost[i][1]-cost[i][2]]+tot[i][0]+tot[i][1]+tot[i][2]);//主件和第一,二件 
            } 
            
        }
        cout<<dp[n];
        return 0;
     } 

    下面是一开始写的假代码,不知道为啥还能混到80分。可能的问题是输入时有可能先输入附件,按我那么做的话附件在前面,不是由选其对应主件递推而来,这个附件肯定就不会选上,所以要排序,1~m应该是先主件后附件,q的值也要改,但不知道哪里有问题...求各位大佬指教。

    #include <bits/stdc++.h>//80分假代码,问题在32行 
    using namespace std;
    int n,m;
    struct good//商品结构体 
    {
        int v;
        int p;
        int q;
        int num; 
    }g[65];
    bool cmp(good a,good b)
    {
        return a.q<b.q;
     } 
    struct state//以状态作为dp数组的元素 
    {
        bool vis[65];
        int val;
    };
    state dp[65][32605];
    int main()
    {
        cin>>n>>m;
        int i,j,k;
        for(i=1;i<=m;i++)
        {
            int v,p,q;
            scanf("%d%d%d",&v,&p,&q);
            g[i].v=v;
            g[i].p=p;
            g[i].q=q;
            g[i].num=i;//方便排序后查找 
        }
        
        
    //    sort(g+1,g+m+1,cmp);//不能sort? 因为排序后原来的下标也变了 good结构体里的q变量也不能用了 但如果不sort的话假设第一个物体就是附件 那么i从1开始肯定拿不到这个物品了 不满足无后效性 所以说必须排序,然排序后如何调整q的值也是问题 
    //    for(i=1;i<=m;i++)
    //    {
    //        for(j=1;j<=m;j++)
    //        {
    //            if(g[i].q==g[j].num&&g[i].q!=0&&g[j].q==0)
    //            {
    //            //    g[i].q=j; 
    //                g[j].q=i;
    //            }
    //        }
    //     } 
         
         
         
        for(i=0;i<=m;i++)
        {
            for(j=0;j<=n;j++)
            {
                dp[i][j].val=0;
                for(k=1;k<=m;k++)dp[i][j].vis[k]=0;
            }
        }
        for(i=1;i<=m;i++)
        {
            for(j=0;j<g[i].v;j++)//不能漏                                                                                                                  
            {
                dp[i][j]=dp[i-1][j];                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
            }
            for(j=g[i].v;j<=n;j++)
            {
                if(g[i].q)//自己是附件 
                {
                    if(dp[i-1][j].val>dp[i-1][j-g[i].v].val+g[i].v*g[i].p)
                    {
                         dp[i][j].val=dp[i-1][j].val;
                         memcpy(dp[i][j].vis,dp[i-1][j].vis,sizeof(bool)*65);
                    }
                    else if(dp[i-1][j].val<=dp[i-1][j-g[i].v].val+g[i].v*g[i].p&&dp[i-1][j-g[i].v].vis[g[i].q])//附件的主件已经选择 
                    {
                        dp[i][j].val=dp[i-1][j-g[i].v].val+g[i].v*g[i].p;
                        memcpy(dp[i][j].vis,dp[i-1][j-g[i].v].vis,sizeof(bool)*65);//一定要整个复制过来 
                        dp[i][j].vis[i]=1;
                    }
                    else
                    {
                        dp[i][j].val=dp[i-1][j].val;
                        memcpy(dp[i][j].vis,dp[i-1][j].vis,sizeof(bool)*65);
                    }        
                }
                else//自己是主件 
                {
                    if(dp[i-1][j].val>dp[i-1][j-g[i].v].val+g[i].v*g[i].p)//不能取等?因为如果相等的话其实应该买这件物品,为以后增加可能 
                    {
                         dp[i][j].val=dp[i-1][j].val;
                         memcpy(dp[i][j].vis,dp[i-1][j].vis,sizeof(bool)*65);
                    }
                    else
                    {
                        dp[i][j].val=dp[i-1][j-g[i].v].val+g[i].v*g[i].p;
                        memcpy(dp[i][j].vis,dp[i-1][j-g[i].v].vis,sizeof(bool)*65);//一定要整个复制过来 
                        dp[i][j].vis[i]=1;
                    }        
                }
            }
        }
        int ans=0;
        state mmax;
        for(i=1;i<=m;i++)
        {
            for(j=1;j<=n;j++)
            {
            //    ans=max(ans,dp[i][j].val);
                if(ans<dp[i][j].val)
                {
                    ans=dp[i][j].val;
                    mmax=dp[i][j];
                }
            }
        }
        cout<<ans;
    }
  • 相关阅读:
    mapreduce 本地调试需要注意的问题
    socket-----爬虫&&文件传输
    多个地点ping服务器
    linux grep命令详解
    关于真多核和加多核&线程由哪几部分组成
    内存溢出和内存泄漏
    指针和引用的区别
    Doxygen的使用,配置及实例
    【转】doxygen+graphviz生成工程中的类继承树及函数调用图
    转载--void指针(void *的用法)
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12343454.html
Copyright © 2011-2022 走看看