HDU--2639--Bone Collector II--01揹包

Bone Collector II

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2464    Accepted Submission(s): 1295
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
 


題意:給你n個骨頭的信息(價值和體積),給你一個體積爲V的揹包,要你求出這個揹包裝骨頭得到的所有價值中第K大的

思索了半天不知道就百度,百度之後還是不懂結果就看接替報告,看了半天看是不知道博主們想說的是什麼,於是就對照代碼對照數據事勁瞅,然後才差不多懵懵懂

解析:常規的01揹包是求的V體積的容器中裝物品得到的最大價值,像這個要求的是第K大的就有點力不從心了,所以要加點料,揹包九講裏邊學來的公式是

f[x]=max[f[x-v]+w,f[x]),要求K大的值肯定要記錄更多數據才行,所以給數組加一維變成f[ ][ ],第二維裏面就用來記錄K個數據,分別是最大遞減到K大,然後直接用01揹包的方法求就是了,本來f[x][1~k]中只有K個數據,對於1~k全部都作上面的那個公式處理一下,然後得到的數據是2*K個,懂吧?分別是f[x][k]和f[x-v][k]+w,然後這些數據取最大的K個記錄下來就行了

其實這個我還是不太懂,驗證了半天就是得不出讓我心安理得的結論,爲什麼這樣就能保證結果中能得出所有值,其中的一些小插曲就不說了,看代碼吧!


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main (void)
{
    int n,v,m,i,j,k,l,t;
    __int64 dp[1111][33],a[2][33],vol[111],val[111];
    scanf("%d",&t);
    while(t--&&~scanf("%d%d%d",&n,&v,&m))
    {
        for(i=0;i<n;i++)
        {
            scanf("%I64d",&val[i]);
        }
        for(i=0;i<n;i++)
        {
            scanf("%I64d",&vol[i]);
        }
        memset(dp,0,sizeof(dp));
        for(i=0;i<n;i++)
        {
            for(j=v;j>=vol[i];j--)
            {
                for(k=0;k<m;k++)	//把第二維裏面的每個數據都記錄一個繼承值和優選值
                {
                    a[0][k]=dp[j][k];	//不選擇裝入第i個物品
                    a[1][k]=dp[j-vol[i]][k]+val[i];	//裝入第i個物品
                }
                int p,q,w;
                p=q=w=0;
                a[0][m]=a[1][m]=-1;	//考慮會出現其中一個數組的去完了的情況,所以末尾-1有妙用
                while(w<m&&(p<m||q<m))
                {
                    if(a[0][p]<a[1][q])
                    {
                        dp[j][w]=a[1][q];
                        q++;
                    }else
                    {
                        dp[j][w]=a[0][p];
                        p++;
                    }
                    if(w==0||dp[j][w]!=dp[j][w-1])	//有重複值
                    w++;
                }
            }
        }
        printf("%I64d\n",dp[v][m-1]);
    }
    return 0;
}

總結:這算是一個新的寫法,至少對於我來說,我還沒有真正弄懂這個做法,只是簡單的記下來了,記下來是沒用的,要理解才行,這兩天就多瞅瞅吧,直到弄明白了再說!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章