1. 程式人生 > >POJ 1252 Euro Efficiency ( 完全背包變形 && 物品重量為負 )

POJ 1252 Euro Efficiency ( 完全背包變形 && 物品重量為負 )

狀態 -a 數組 nbsp pre body pos n) ide

題意 : 給出 6 枚硬幣的面值,然後要求求出對於 1~100 要用所給硬幣湊出這 100 個面值且要求所用的硬幣數都是最少的,問你最後使用硬幣的平均個數以及對於單個面值所用硬幣的最大數。

分析 :

問題建模就是屬於完全背包了,但是和普通的完全背包不一樣,這題可以使用硬幣的負數值,其實面對負數面值的情況,解決方法將更新數序和普通完全背包的更新順序相反即可,然後正反更新兩次就能得出最後的答案了。在普通物品重量只有正數的情況下對於一個 dp[i] 是從下標值小於 i 的狀態轉移而來,為了達到物品能夠無限取這一條件 ( 可以參考《挑戰程序設計競賽》裏面對於完全背包遞推式子的解釋 ) ,而負數重量的時候 dp[i] 是從下標值大於 i 的狀態轉移而來,故更新方向需和正數重量相反,其實這麽說也是很抽象的,建議還是先去看看《挑戰》裏面對於完全背包原來的分析可能比較好理解。然後有一點值得註意的就是如果 dp 數組下標的更新需要開到起碼 1400 ==> 考慮 1、96、97、98、99、100 這一個例子,如果要湊成 ( 1 + 96 ) / 2 的話大概需要 25個左右 也就是需要使用大概需要25/2=13個面值為 100 的硬幣,價值能達到 1300.....

技術分享圖片
import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import java.math.*;
import java.util.Arrays;
public class Main {
    public static void main(String[] args){
        Scanner cin = new Scanner (new BufferedInputStream(System.in));
        int[] dp = new int[2333];
        int
[] arr1 = new int[6]; int[] arr2 = new int[6]; int nCase; final int num = 6; nCase = cin.nextInt(); for(int Case=1; Case<=nCase; Case++){ for(int i=0; i<num; i++) arr1[i] = cin.nextInt(); for(int i=0; i<num; i++) arr2[i] = -arr1[i];
for(int i=0; i<2333; i++) dp[i] = 1000000; dp[0] = 0; for(int i=0; i<num; i++) for(int j=arr1[i]; j<=2000; j++) dp[j] = Math.min(dp[j], dp[j-arr1[i]] + 1); for(int i=0; i<num; i++) for(int j=2000-arr2[i]; j>=0; j--) dp[j] = Math.min(dp[j], dp[j-arr2[i]] + 1); int MaxNUM = 0; double Sum = 0; for(int i=0; i<=100; i++){ MaxNUM = Math.max(dp[i], MaxNUM); Sum += (double)dp[i]; } System.out.printf("%.2f %d\n", Sum/100.0, MaxNUM); } } }
View Code

POJ 1252 Euro Efficiency ( 完全背包變形 && 物品重量為負 )