zju 2955 DP + 贪心归约

来源:互联网 发布:软件版权声明怎么写 编辑:程序博客网 时间:2024/05/01 22:11

无限重数多重背包,

问题描述:有物品集V[0...n-1],每个物品都有无限个,背包大小为C,求取得C大小背包的最小物品个数。

f[0]=0;
f[i]=min{f[i-V[j]]+1 | j=0,1,...n-1 };

当C很大n不大时的优化方法,设vm=max{V[0...n-1]},根据Frobenius Number进行保守估算,当C>=vm*n是恒有解的
因此,只要DP求得C属于[0,vm*n+vm)上的最优解,当C<vm*n+vm时,直接输入最优解,
当C>=vm*n+vm时,一定可以贪心归约到区间[vm*n,vm*n+vm)上。

#include <iostream>
#include <algorithm>
using namespace std;

int dp[10001];
int M[100];

int main()
{
 int T;
 scanf("%d",&T);
 while(T--){
  int m,n;
  scanf("%d%d",&m,&n);
  for(int i=0;i<m;i++){
   scanf("%d",&M[i]);
  }
  fill(dp,dp+10001,100000);
  dp[0]=0;
  for(int i=1;i<=10000;i++){
   for(int j=0;j<m;j++){
    if(i>=M[j]){
     dp[i]<?=dp[i-M[j]]+1;  //如果dp[i] < dp[i-M[j]]+1 ,则dp[i] = dp[i-M[j]]+1
    }
   }
  }
  if(n<=10000){
   printf("%d/n",dp[n]<100000?dp[n]:-1);
  }
  else {
   int x=*max_element(M,M+m);
   int k=(n-10000+x-1)/x;               //贪心归约到区间内
   n-=x*k;
   printf("%d/n",dp[n]<100000?dp[n]+k:-1);//如果无限重数多重背包,
  }
 }
}

原创粉丝点击