hdu 2844 Coins 多重背包+二进制优化

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
 



开始没用二进制优化果断TLE啊,我还以为是我写的不对,后来一百度明白了,学习了一下二进制详细解释看下面

初始化分两种情况
1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w] = -INF;
2、如果不需要正好装满 f[0~v] = 0;

多重背包问题要求很简单,就是每件物品给出确定的件数,求
可得到的最大价值

多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用
分解成若干个件数的集合,这里面数字可以组合成任意小于等于C
的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可
以用数字的二进制形式来解释
比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以
组合成任意小于等于7 的数,而且每种组合都会得到不同的数
15 = 1111 可分解成 0001 0010 0100 1000 四个数字
如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成
7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13
的数,虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种
思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。



下面是不带二进制的,这是TLE的

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
    int value,num;
} q[2000];
int f[2500000+5];
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m))
    {
        if(n==0&&m==0)
            break;
        for(int i=1; i<=n; i++)
            scanf("%d",&q[i].value);
        int total=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&q[i].num);
            total+=q[i].value*q[i].num;
        }
        total=min(m,total);
        memset(f,0,sizeof(f));
        for(int i=1; i<=n; i++)
            {
                if(q[i].value>total)
                    continue;
                for(int k=0; k<=q[i].num; k++)
                {

                    for(int p=total; p>=q[i].value; p--)
                    f[p]=max(f[p],f[p-q[i].value]+q[i].value);
                }
            }

        int s=0;
        for(int i=1; i<=total; i++)
            if(f[i]==i)
                s++;
        printf("%d\n",s);
    }
    return 0;
}
下面是加上二进制以后的
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
    int value,num;
}q[200000];
int v[2000000],f[200000];
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m),n||m)
    {
        for(int i=0;i<n;i++)
            scanf("%d",&q[i].value);
        for(int i=0;i<n;i++)
            scanf("%d",&q[i].num);
            int cnt=0;
            for(int i=0;i<n;i++)
            {
                int k=1;
                while(k<q[i].num)
                {
                    v[cnt++]=q[i].value*k;
                    q[i].num-=k;
                    k*=2;
                }
                k=q[i].num;
                v[cnt++]=q[i].value*k;
            }
            memset(f,0,sizeof(f));
            for(int i=0;i<cnt;i++)
                for(int j=m;j>=v[i];j--)
                f[j]=max(f[j],f[j-v[i]]+v[i]);
            int s=0;
            for(int i=1;i<=m;i++)
                if(f[i]==i)
                s++;
            printf("%d\n",s);
    }
    return 0;
}
下面是看了别人的据说是模板性质的:

#include<iostream>
#include<stdio.h>
using namespace std;
int dp[100010];//注意数组大小
int value[2000],num[2000];
int n,m;
int max(int a,int b)
{
	if(a>b)
		return a;
	else
		return b;
}
void ZeroOnePack(int value,int weight)
{
	int i;
	for(i=m;i>=value;i--)
		dp[i]=max(dp[i],dp[i-value]+weight);
}
void CompletePack(int value,int weight)
{
	int i;
		for(i=value;i<=m;i++)
		dp[i]=max(dp[i],dp[i-value]+weight);
}
void MultiplePack(int value,int weight,int num)
{
	if(value*num>=m) //转化为完全背包
		CompletePack(value,weight);
	else  //二进制优化
	{
		int k=1;
		while(k<=num)
		{
			ZeroOnePack(k*value,k*weight);
			num-=k;
			k<<=1;
		}
		ZeroOnePack(num*value,num*value);
	}
}
int main()
{
	while(scanf("%d %d",&n,&m))
	{
		if(n+m==0)
			break;
		int i;
		for(i=1;i<=m;i++) 
			dp[i]=-10000000;    //复制为最小
        dp[0]=0;	
		for(i=0;i<n;i++)
		  scanf("%d",&value[i]);		
		for(i=0;i<n;i++)
		  scanf("%d",&num[i]);
		for(i=0;i<n;i++)
			MultiplePack(value[i],value[i],num[i]); //多重背包
		int ans=0;
		for(i=1;i<=m;i++) //统计
		{
			if(dp[i]>0)
               ans++;
		}
		printf("%d\n",ans);


	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Eclipse二进制文件是指由Eclipse集成开发环境生成的可执行文件。在Linux下,Eclipse生成的二进制文件通常是没有扩展名的,如上述引用所示。在使用Eclipse编译和运行项目时,如果项目名包含扩展名(例如.hdu.c),则Eclipse可能无法正确识别该文件为二进制可执行文件。 这可能导致在运行时出现找不到二进制文件的错误。解决办法有两种:一是避免使用带有扩展名的项目名,另一种是手动创建一个运行配置,将命令写死以确保正确识别为二进制文件。 需要注意的是,上述讨论中的EclipseParser库是一个用于验证和读取Eclipse二进制文件内容的DLL库,它是通过按照二进制格式编写的。这个库可以验证和读取Eclipse二进制文件中的EGRID、INIT、UNRST等内容。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [linux下eclipse c++运行不了提示找不到二进制文件的解决方法](https://blog.csdn.net/bjrxyz/article/details/8974483)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Eclipse油藏数值模拟软件的二进制文件格式解析](https://blog.csdn.net/slofslb/article/details/119176891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值