【揹包】POJ3260

The Fewest Coins
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 4464   Accepted: 1334

Description

Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he always pays for his goods in such a way that the smallest number of coins changes hands, i.e., the number of coins he uses to pay plus the number of coins he receives in change is minimized. Help him to determine what this minimum number is.

FJ wants to buy T (1 ≤ T ≤ 10,000) cents of supplies. The currency system has N (1 ≤ N ≤ 100) different coins, with values V1V2, ..., VN (1 ≤ Vi ≤ 120). Farmer John is carrying C1 coins of value V1C2coins of value V2, ...., and CN coins of value VN (0 ≤ Ci ≤ 10,000). The shopkeeper has an unlimited supply of all the coins, and always makes change in the most efficient manner (although Farmer John must be sure to pay in a way that makes it possible to make the correct change).

Input

Line 1: Two space-separated integers: N and T
Line 2: N space-separated integers, respectively V1V2, ..., VN coins (V1, ...VN
Line 3: N space-separated integers, respectively C1C2, ..., CN

Output

Line 1: A line containing a single integer, the minimum number of coins involved in a payment and change-making. If it is impossible for Farmer John to pay and receive exact change, output -1.

Sample Input

3 70
5 25 50
5 2 1

Sample Output

3

Hint

Farmer John pays 75 cents using a 50 cents and a 25 cents coin, and receives a 5 cents coin in change, for a total of 3 coins used in the transaction.

Source


【翻譯】             

Description

農夫John想到鎮上買些補給。爲了高效地完成任務,他想使硬幣的轉手次數最少。即使他交付的硬幣數與找零得到的的硬幣數最少。

 John想要買T(1<=T<=10000)元錢的東西。有N(1<=n<=100)種貨幣參與流通,面值分別爲V1,V2..Vn (1<=Vi<=120)JohnCi個面值爲Vi的硬幣(0<=Ci<=10000)。我們假設店主有無限多的硬幣,並總按最優方案找零。Inputfewcoins.in)

*Line 1: 兩個整數 N T

*Line 2: N 個數,表示 V1, V2, ..Vn

*Line 3: N 個數,表示 C1, C2, ..Cn

Outputfewcoins.out)

SampleInput
3 70
5 25 50
5 2 1

Sample Output
3

【題解】支付時硬幣數量有限制,爲多重揹包問題,通過二進制方法轉化爲01揹包求解。找零時,硬幣數量無限制,爲完全揹包問題。對兩問題分別求解,然後找出差額爲T時,兩者和的最小值即爲所示。 (考試的時候我先做支付再做找零 WA了 答案是兩者和的最小值,不是min(支付)+min(支付-t))


其中:給錢上界爲:T+maxValue^2,其中maxValue爲最大硬幣面值。證明:反證法。假設存在一種支付方案,John給的錢超過T+maxValue^2, 則售貨員找零超過maxValue^2,則找的硬幣數目超過maxValue個,將其看作一數列,求前n項和sum(n),根據鴿巢原理,至少有兩 個對maxValue求模的值相等,假設爲sum(i)和sum(j),i<j,則i+1...j的硬幣面值和爲maxValue的倍數,同理,John給的錢中也有 一定數量的硬幣面值和爲maxValue的倍數,則這兩堆硬幣可用數量更少的maxValue面值硬幣代替,產生更優方案 

#include<cstdio> 
#include<climits>
using namespace std;
int t,n,i,limit,ans,f1[500000],f2[500000],c[101],v[101],s=0;
#define INF 999999
      
void Zeroonepack(int w,int vn){
    for (int j=limit;j>=w;j--) 
       if (f2[j-w]+vn<f2[j])  f2[j]=f2[j-w]+vn;
}
  
void Multiplepack(int num,int w){
     int k=1;
     while (k<num){
       Zeroonepack(k*w,k);
       num-=k;
       k*=2;
     }
     if (num) Zeroonepack(num*w,num);
}
             
void fewgive(){ // 給錢  上界maxv^2+t 多重揹包二進制優化 
  limit+=t;
  for (i=1;i<=limit;i++) f2[i]=INF;
  f2[0]=0; 
  for (i=1;i<=n;i++) Multiplepack(c[i],v[i]);
  ans=INF;
  for (i=t;i<=limit;i++) 
    if (f1[i-t]+f2[i]<ans)  ans=f1[i-t]+f2[i];
}

void fewchange(){  //找零 上界maxv^2 完全揹包 
  int j;
  for (j=1;j<=limit;j++) f1[j]=INF;
  f1[0]=0;
  for (i=1;i<=n;i++) 
   for (j=v[i];j<=limit;j++)
     if (f1[j-v[i]]+1<f1[j]) f1[j]=f1[j-v[i]]+1;
}     
     

void init(){
   scanf("%d%d",&n,&t);
   for (i=1;i<=n;i++) { 
       scanf("%d",&v[i]);   
      if (v[i]>limit) limit=v[i]; 
      }
   limit*=limit;
   for (i=1;i<=n;i++) {
         scanf("%d",&c[i]);  
          s+=v[i]*c[i];
          }
}   
    
int main()
{
    freopen("fewcoins.in","r",stdin);
    freopen("fewcoins.out","w",stdout);
    init();
    if (s<t) printf("-1\n");
    else {
      fewchange();   
      fewgive();
      if (ans==INF) printf("-1\n");
       else  printf("%d\n",ans);
    }
}



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