2639骨頭問題2(01揹包的第k大值)
阿新 • • 發佈:2019-02-07
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 ).
對01揹包理解還是不透徹,看了大神的程式碼都半天沒反應過來。 大神給dp陣列加了一個維度,存放最大的k個值。 只有一個物品時候,只有放和不放兩個值,存到k陣列。這是揹包的兩個可能的狀態,並排序 當有兩個物品時候,在第一個放和不放狀態上又可以有放和不放。以此類推。所以有了k的迴圈,每次都把放和不放的狀態與原來的幾種狀態依次相加,得到新的狀態 因為dp陣列初始化都是0,是有序的,每次放完a,b中間陣列都是嚴格遞減的,原因是dp[j][k]一定大於dp[j][k+1],所以無論取dp[j][k]或者dp[j][k-vol[i]]+val[i]都是嚴格遞減 所以排序時候可以用類似歸併排序的合併方法。大神把排序的陣列最後一個設為負數,就不用管邊界問題,非常好的方法。 每次找出前k個最優值,然後存入dp陣列。如果不滿k個,則後面的是0,對下一次決策沒影響,到時候對結果也沒影響,因為結果讓不滿k個輸出0,只是排序的時候注意一下去重。上大神程式碼 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXN 105
#define MAXV 1005
int MyMax(int a,int b)
{
return (a>b?a:b);
}
int main()
{
int t,n,v,m;
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
int i,j,k;
int val[6],vol[6],dp[11][3];
int a[35],b[35];
scanf("%d%d%d",&n,&v,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&val[i]);
}
for(i=1;i<=n;i++)
{
scanf("%d",&vol[i]);
}
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
for(j=v;j>=vol[i];j--)
{
for(k=1;k<=m;k++)
{
a[k]=dp[j-vol[i]][k]+val[i];
b[k]=dp[j][k];
}
int x,y,z;
x=y=z=1;
a[k]=b[k]=-1;
while(z<=m&&(y<=m||x<=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\n",dp[v][m]);
}
}
return (0);
}
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
對01揹包理解還是不透徹,看了大神的程式碼都半天沒反應過來。 大神給dp陣列加了一個維度,存放最大的k個值。 只有一個物品時候,只有放和不放兩個值,存到k陣列。這是揹包的兩個可能的狀態,並排序 當有兩個物品時候,在第一個放和不放狀態上又可以有放和不放。以此類推。所以有了k的迴圈,每次都把放和不放的狀態與原來的幾種狀態依次相加,得到新的狀態 因為dp陣列初始化都是0,是有序的,每次放完a,b中間陣列都是嚴格遞減的,原因是dp[j][k]一定大於dp[j][k+1],所以無論取dp[j][k]或者dp[j][k-vol[i]]+val[i]都是嚴格遞減 所以排序時候可以用類似歸併排序的合併方法。大神把排序的陣列最後一個設為負數,就不用管邊界問題,非常好的方法。 每次找出前k個最優值,然後存入dp陣列。如果不滿k個,則後面的是0,對下一次決策沒影響,到時候對結果也沒影響,因為結果讓不滿k個輸出0,只是排序的時候注意一下去重。上大神程式碼 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXN 105
#define MAXV 1005
int MyMax(int a,int b)
{
return (a>b?a:b);
}
int main()
{
int t,n,v,m;
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
int i,j,k;
int val[6],vol[6],dp[11][3];
int a[35],b[35];
scanf("%d%d%d",&n,&v,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&val[i]);
}
for(i=1;i<=n;i++)
{
scanf("%d",&vol[i]);
}
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
for(j=v;j>=vol[i];j--)
{
for(k=1;k<=m;k++)
{
a[k]=dp[j-vol[i]][k]+val[i];
b[k]=dp[j][k];
}
int x,y,z;
x=y=z=1;
a[k]=b[k]=-1;
while(z<=m&&(y<=m||x<=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\n",dp[v][m]);
}
}
return (0);
}