poj3260 The Fewest Coins

来源:互联网 发布:类似知乎天涯的网站 编辑:程序博客网 时间:2024/04/30 01:14

题意:FJ同学去买东西,东西的价值为T,他和卖家都有N种金币,FJ希望交易完成时金币变化最小。

求最少的金币变化数量。FJ的金币个数有限,卖家的金币数目无限。

思路:背包问题,FJ的每种金币个数有限可以看做是多重背包问题,卖家的金币数目无限可以看做是完全背包问题。

设DP1[i]为FJ付款为i时的最小金币数,设DP2[i]为卖家找钱为i时的最小金币数。

则DP1[i+T]+DP2[i]就是所求的最小金币变化数量(DP1用多重背包求解,DP2用完全背包求解)

PS:这里的背包求得是最小价值,且要恰好装满。故初始化数组时应 DP[0]=0,DP[1~MAXN]=INT_MAX;

/******************* * Author;fisty * Data:2014-11-18 * poj3260 *完全背包+分组背包 *******************/#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define MAX_N  224000#define INF 1000000000int dp1[MAX_N],dp2[MAX_N];int v[120], c[10000];int n,m;int m_sum = 0;//FJ可以付的最多钱数int  solve(){        for(int i = 0;i <= m_sum; i++){                dp2[i] = INF;                dp1[i] = INF;        }        dp1[0] = 0;        dp2[0] = 0;        //对payment实行分组背包        for(int i = 1;i <= n; i++){                if(v[i]*c[i] >= m_sum){                        for(int j = v[i]; j <= m_sum; j++){                                dp1[j] = min(dp1[j], dp1[j-v[i]] + 1);                        }                }else{                        int k = 1;                        while(k < c[i]){                                for(int j = m_sum; j >= k*v[i]; j--){                                        dp1[j] = min(dp1[j], dp1[j-k*v[i]] + k);                                }                                c[i] -= k;                                k *= 2;                        }                                        for(int j = m_sum; j >= c[i]*v[i]; j--){                                dp1[j] = min(dp1[j], dp1[j-v[i]*c[i]] + c[i]);                        }                }        }        //对charge进行完全背包        for(int i = 1;i <= n; i++){                for(int j = v[i]; j <= m_sum; j++){                        dp2[j] = min(dp2[j-v[i]]+1, dp2[j]);                }        }        int ans = INF;        for(int i = 0;i <= m_sum - m; i++){                ans = min(ans, dp1[i+m] + dp2[i]);        }        return ans == INF ? -1 : ans;}int main(){        scanf("%d%d", &n, &m);        for(int i = 1;i <= n; i++){                scanf("%d", &v[i]);                m_sum = max(m_sum, v[i]);        }        for(int i = 1;i <= n; i++){                scanf("%d", &c[i]);        }        m_sum = m_sum * m_sum + m + 1;        int ans = solve();        printf("%d\n", ans);        return 0;}


0 0
原创粉丝点击