zoukankan      html  css  js  c++  java
  • HDU 2639(01背包求第K大值)

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=2639

    Bone Collector II

    Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 5817    Accepted Submission(s): 3067


    Problem Description
    The title of this problem is familiar,isn't it?yeah,if you had took part in the "Rookie Cup" competition,you must have seem this title.If you haven't seen it before,it doesn't matter,I will give you a link:

    Here is the link:http://acm.hdu.edu.cn/showproblem.php?pid=2602

    Today we are not desiring the maximum value of bones,but the K-th maximum value of the bones.NOTICE that,we considerate two ways that get the same value of bones are the same.That means,it will be a strictly decreasing sequence from the 1st maximum , 2nd maximum .. to the K-th maximum.

    If the total number of different values is less than K,just ouput 0.
     
    Input
    The first line contain a integer T , the number of cases.
    Followed by T cases , each case three lines , the first line contain two integer N , V, K(N <= 100 , V <= 1000 , K <= 30)representing the number of bones and the volume of his bag and the K we need. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
     
    Output
    One integer per line representing the K-th maximum of the total value (this number will be less than 231).
     
    Sample Input
    3 5 10 2 1 2 3 4 5 5 4 3 2 1 5 10 12 1 2 3 4 5 5 4 3 2 1 5 10 16 1 2 3 4 5 5 4 3 2 1
     
    Sample Output
    12 2 0
     
    Author
    teddy
     分析:
    做的第一个背包求k大值问题。。。。
    参考了大佬的博客好久:
    这个是HUDU2602的变形题,HDU2602题参考我的这篇博客:
    原来我们要求的是最大值,现在我们要求的是第K大值
     
    参加资料:
    实际上,一个正确的状态转移方程的求解过程遍历了所有可用的策略,也就覆盖了问题的所有方案。只不过由于是求最优解,所以其 它在任何一个策略上达不到最优的方案都被忽略了。如果把每个状态表示成一个大小为K的数组,并在这个数组中有序的保存该状态可取到的前K个最优值。那么, 对于任两个状态的max运算等价于两个由大到小的有序队列的合并。另外还要注意题目对于“第K优解”的定义,将策略不同但权值相同的两个方案是看作同一个解还是不同的解。如果是前者,则维护有序队列时要保证队列里的数没有重复的。
     
    int dp[max_v][35];//dp[j][k] 代表背包容量为j时 第k大值
     
    我的理解:
    普通的01背包问题求解的时候其实遍历了所有可用的策略,但是不是最优的方案就忽略了,没有记录下来,比如max/min,只取了最大或者最小值,现在我们需要用到所有的策略,那么我们就用两个数组将原来忽略的值记录下来,将两个数组合并起来(降序,注意去重),然后将合并的数组存到dp[j][x] x属于从1到k
    注意点:
    1.合并数组要去重,因为策略不同但是权值相同的方案是看成同一个解的
    去重和排序不能采用set,不然超时。。。
     
    具体参考代码:
    #include<bits/stdc++.h>
    using namespace std;
    #define max_v 10005
    int v[max_v],w[max_v];
    int dp[max_v][35];//dp[j][k] 代表背包容量为j时 第k大值
    int a[max_v],b[max_v];
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n,c,m;
            scanf("%d %d %d",&n,&c,&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&v[i]);
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&w[i]);
            }
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++)
            {
                for(int j=c;j>=w[i];j--)
                {
                    int k;
                   // set <int,greater<int> > s;
                    for(k=1;k<=m;k++ )
                    {
                       // a[k]=dp[j-w[i]][k]+v[i];
                       // b[k]=dp[j][k];
                       b[k]=dp[j-w[i]][k]+v[i];
                       a[k]=dp[j][k];
                       //s.insert(b[k]);
                       //s.insert(a[k]);
                    }
                 /*   set<int,greater<int> >::iterator it;
                    int z=1;
                    for(it=s.begin();it!=s.end();it++)
                    {
                        dp[j][z++]=*it;
                    }
                    //使用set集合会超时 偷懒是不可能的了
                    */
    
                    int x,y,z;
                    x=y=z=1;
                    a[k]=b[k]=-1;
                    while(z<=m&&(x<=m||y<=m))
                    {
                        if(a[x]>b[y])
                        {
                            dp[j][z]=a[x++];
                        }else
                        {
                            dp[j][z]=b[y++];
                        }
                        if(dp[j][z]!=dp[j][z-1])
                        {
                            z++;
                        }
                    }
                }
            }
            printf("%d
    ",dp[c][m]);
        }
        return 0;
    }
  • 相关阅读:
    存货核算中的加权平均
    System stored procedures
    javascript中replace与正则表达式
    AfxGetApp 解剖
    MFC中的文字输出
    函数指针的应用
    MFC消息处理与SDK消息处理
    在本地机器上获取root权限
    文件内容读取
    Linux下安装windows系统的方法
  • 原文地址:https://www.cnblogs.com/yinbiao/p/9099194.html
Copyright © 2011-2022 走看看