您的位置:首页 > 其它

求01背包的第k大解

2013-04-14 16:40 134 查看
这是一道求背包问题第k次大解。思路稍有点变法,就是在递归的过程中,分别用两个数组记录两种状态(选择或不选择),并且只要记录前k次。在这两个数组中都是前k次可能的最优解。所以我们只要把这两个数组做比较,一直排到k就行了,另外,对于递归问题,我们只要抓住某个状态的前后关系,把复杂问题简单化,不必去纠结全过程的状态,应为程序在运行时,递归过程是用堆栈实现的,其变化复杂,没必要每步弄懂。重点在于抓住前后规律和设计思路就可以了。

#include<stdio.h>
#include<string.h>
int dp[1001][50],wi[100],di[100];
int n,m,k;

void BK()
{
int a[50],b[50];           //用于记录当体积为j时,它的价值量。
int i,j,h;
int x,y,z;
for(i=0;i<n;i++)
for(j=m;j>=wi[i];j--)
{
for(h=1;h<=k;h++)          //把前k个一次比较排序,不必要全部排完。
{
a[h]=dp[j-wi[i]][h]+di[i];   //选择两次状态,应为它的优解,只可能在这两者选择。
b[h]=dp[j][h];               //要么选择一个,要么不选择。
}
x=y=z=1,a[h]=b[h]=-1;              //从两个数组中把前k的值排序,此时h>K,就不必管他了,令它为-1是应为
while(z<=k&&(a[x]!=-1||b[y]!=-1))  // 在选的时候,以保证x,y不会超出k范围。
{                                //这个循环就是从前k个里面选出最优解(降序)。
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[m][k]);
}

int main()
{
int t,i;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(i=0;i<n;i++)
scanf("%d",&di[i]);
for(i=0;i<n;i++)
scanf("%d",&wi[i]);
memset(dp,0,sizeof(dp));
BK();
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: