zoukankan      html  css  js  c++  java
  • POJ1807&&1276

    DP专题下的背包专题

    其实就是PJ的那些东西了

    主流的背包有三种:01背包,完全背包和多重背包

    其中01背包和完全背包的转移就比较经典了,而多重背包也是在前两者基础上演变一下即可

    1837

    题意:有一个天平,上面有一些地方有钩子可以挂钩码。让你求当所有钩码都挂上去时共有多少种方案使天平平衡

    很简单,每个钩码只能用一次,所以我们设f[i][j]表示用完前i个钩码天平的状态为j的方案数

    注意此处j表示天平的状态,若j<0表示向左倾,j>0表示向右倾,当然,0表示平衡

    于是转移便为:

    f[i][j]+=f[i-1][j-w[i]*d[k]](1<=i<=n;k<=c)
    

    这里为了处理下标为负数的情况只需要都加上一个数即可

    CODE

    #include<cstdio>
    using namespace std;
    const int MAX_TILT=7500,N=25;
    int m,n,d[N],w[N];
    long long f[N][(8000<<1)+10];
    inline char tc(void)
    {
    	static char fl[100000],*A=fl,*B=fl;
    	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0; char ch=tc(); bool flag=1;
    	while (ch<'0'||ch>'9') { if (ch=='-') flag=0; ch=tc(); }
    	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    	x=flag?x:-x;
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	register int i,j,k;
    	read(m); read(n);
    	for (i=1;i<=m;++i)
    	read(d[i]);
    	for (i=1;i<=n;++i)
    	read(w[i]);
    	for (f[0][MAX_TILT]=1,i=1;i<=n;++i)
    	for (j=0;j<=MAX_TILT<<1;++j)
    	for (k=1;k<=m;++k)
    	if (j>=d[k]*w[i]) f[i][j]+=f[i-1][j-d[k]*w[i]];
    	printf("%lld",f[n][MAX_TILT]);
    	return 0;
    }
    

    1276

    题意:给你一些钱的价值和它的数量,还有一个最大的价值。让你求最接近最大的价值且不超过最大的价值的价值和

    布尔型多重背包即可

    f[j]表示能否得到j这种价值,然后分情况做01背包和完全背包即可

    这里对于01背包有一个优化:二进制分组

    就是把一个数拆成几个2的幂次的数然后达到将原来的1~num[i]的枚举变成了log级别,一个实用的技巧

    这里的多重背包模板也是非常不错的(清新自然),可以看一下

    CODE

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAX_M=100005,N=15;
    int num[N],w[N],m,n;
    bool f[MAX_M];
    inline void pack_01(int w)
    {
    	for (register int i=m;i>=w;--i)
    	f[i]|=f[i-w];
    }
    inline void pack_cpt(int w)
    {
    	for (register int i=w;i<=m;++i)
    	f[i]|=f[i-w];
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	register int i;
    	while (scanf("%d%d",&m,&n)!=EOF)
    	{
    		memset(f,0,sizeof(f));
    		for (f[0]=1,i=1;i<=n;++i)
    		{
    			scanf("%d%d",&num[i],&w[i]);
    			if (num[i]*w[i]>=m) pack_cpt(w[i]); else
    			{
    				int k=1;
    				while (k<num[i])
    				{
    					pack_01(w[i]*k);
    					num[i]-=k; k<<=1;
    				}
    				pack_01(w[i]*num[i]);
    			}
    		}
    		for (i=m;i>=0;--i)
    		if (f[i]) { printf("%d
    ",i); break; }
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java:API文档;文档注释中的javadoc标记;官方API;自己动手给项目建一个API文档
    Java:配置环境(Mac)——MySQL
    Java:配置环境(Mac)——Tomcat
    Java:配置环境(Mac)——Eclipse;修改JDK版本后,Eclipse打不开
    Java:配置环境(Mac)——JDK
    Git:九、删除项目
    Git:修改Git Bash默认打开位置(win10)
    操作系统:diskpart常用指令(使用diskpart实现分区管理)
    人生第一次离职
    C++ std::thread概念介绍
  • 原文地址:https://www.cnblogs.com/cjjsb/p/8909256.html
Copyright © 2011-2022 走看看