Coins(多重背包+二进制优化)

Problem Description
Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.

You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.

Input
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.

Output
For each test case output the answer on a single line.

Sample Input
3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0

Sample Output
8
4
还有R和U的总结就不写了;总结基本都包括在下面了;
题意:给你n种硬币的数量和价值,让你求组成小于等于m钱数的组成方案数;
解题思路:第一遍写超时了,本来想不写了的,赶紧写ACM-steps,过了好长时间上课老师讲了二进制优化才,才有了思路,这里需要解释一下二进制优化:任何一个数都可以用二进制数+非二进制数来表示,比如10可以表示为1+2+4+3;利用这一个原理将双重循环的背包转化为单重循环的01背包问题,这样可以大大的节省时间;在状态转移的过程中需要做一个判断,当前钱的总价值是不是超过要求钱数,超过了,就是一个完全背包问题,没超过就可以转化为01背包问题;dp[i]表示不超过i钱数的能凑出来最大钱数,最后只要dp[i]==i;就是一种方案;
感悟:背包问题需要时间来理解。时间越长有的东西理解的越深刻啊;
代码:
#include
#define N 20010
using namespace std;
int v[N],dp[N*100],w[N],n,m;
void zero_onebag(int v)//01背包
{
    for(int i=m;i>=v;i--)
        dp[i]=max(dp[i],dp[i-v]+v);
}
void complet_bag(int v)//完全背包
{
    for(int i=v;i<=m;i++)
        dp[i]=max(dp[i],dp[i-v]+v);
}
void multiply_bag(int v,int k)//多重背包
{
    if(k*v>=m)
    {
        complet_bag(v);
        return ;
    }
    int d=1;
    while(d
    {
        zero_onebag(d*v);
            k-=d;
        d<<=1;
    }
    zero_onebag(k*v);
}
int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        //cout<<n<<" "<<m<<endl;
        for(int i=0;i
            scanf("%d",&v[i]);
        for(int i=0;i
            scanf("%d",&w[i]);
        memset(dp,0,sizeof dp);
        for(int i=0;i
            multiply_bag(v[i],w[i]);
        int ans=0;
        //for(int i=1;i<=m;i++)
        //    cout<<dp[i]<<" ";
        //cout<<endl;
        for(int i=1;i<=m;i++)
            if(dp[i]==i)
            ans++;
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2016-05-25 10:56  勿忘初心0924  阅读(237)  评论(0编辑  收藏  举报