Bone Collector II
題意:給你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;
}
總結:這算是一個新的寫法,至少對於我來說,我還沒有真正弄懂這個做法,只是簡單的記下來了,記下來是沒用的,要理解才行,這兩天就多瞅瞅吧,直到弄明白了再說!