zoukankan      html  css  js  c++  java
  • 浅谈背包【复习】

    二进制优化分组背包:

    http://acm.hdu.edu.cn/showproblem.php?pid=2844

    分析:没什么好说的就是模板

    code by wzxbeliever:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #define ll long long
    #define il inline
    #define ri register int
    #define lowbit(x) x&(-x)
    using namespace std;
    const int maxn=105;
    const int maxx=100005;
    int n,m,cnt,ans;
    int dp[maxx],v[maxn*40],val[maxn],num[maxn];
    int main(){
    	scanf("%d%d",&n,&m);
    	while(n||m){
    	cnt=ans=0;
    	memset(dp,0,sizeof dp);
    	for(ri i=1;i<=n;i++)scanf("%d",&val[i]);
    	for(ri i=1;i<=n;i++)scanf("%d",&num[i]);
    	for(ri i=1;i<=n;i++)
    		for(ri j=1;j<=num[i];j<<=1){
    			if(j<=num[i])num[i]-=j,v[++cnt]=j*val[i];
    			if(num[i])v[++cnt]=num[i]*val[i];
    		}
    	dp[0]=1;
    	for(ri i=1;i<=cnt;i++)
    	for(ri j=m;j>=v[i];j--)
    	dp[j]|=dp[j-v[i]];
    	for(ri i=1;i<=m;i++)
    	if(dp[i])ans++;
    	printf("%d
    ",ans);
    	scanf("%d%d",&n,&m);
    	}
    	return 0;
    }
    
    

    https://www.luogu.org/problem/P2851

    分析:

    约翰能对各种硬币使用的次数是有限的,于是对约翰做多重背包。

    而老板对各种硬币的使用次数是无限的,于是对老板做完全背包。

    然后在min出最小的答案

    关键就在于没有上限啊

    根据抽屉原理+同余知识,可得到这个上限为max{val[i]*val[i]}(wo bu hui zheng ming)

    code:

    #include <cstdio>
    #include <cstring>
    const int maxT=10000+10;
    const int maxn=100+5;
    const int maxv=120;
    int f[maxT+maxv*maxv],g[maxT+maxv*maxv];
    int v[maxn],c[maxn];
    inline int max(int x,int y) {return x>y?x:y;}
    inline int min(int x,int y) {return x<y?x:y;}
    int main()
    {
        int n,t;
        scanf("%d%d",&n,&t);
        for (int i=1;i<=n;i++)
            scanf("%d",&v[i]);
        int sum=0,mx=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&c[i]);
            sum+=c[i]*v[i];
            mx=max(mx, v[i]*v[i]);
        }
        if (sum<t)
        {
            printf("-1
    ");
            return 0;
        }
        memset(g, 0x3f, sizeof(g));
        memset(f, 0x3f, sizeof(f));
        g[0]=0;
        f[0]=0;
        for (int i=1;i<=n;i++)
            for (int j=v[i];j<=mx;j++)
                g[j]=min(g[j], g[j-v[i]]+1);
        for (int i=1;i<=n;i++)
        { 
            for (int j=1;j<=c[i];j<<=1)
            {
                for (int k=t+mx;k>=j*v[i];k--)//倒过来更新(实际上是拆分成01背包的形式) 
                    f[k]=min(f[k], f[k-j*v[i]]+j);
                c[i]-=j;
            }
            if (c[i])//还有剩余的没更新 
                for (int k=t+mx;k>=c[i]*v[i];k--)
                    f[k]=min(f[k], f[k-c[i]*v[i]]+c[i]);
        }
        int ans=0x3f3f3f3f;
        for (int i=t;i<=t+mx;i++)
            ans=min(ans, f[i]+g[i-t]);
        printf("%d
    ",ans==0x3f3f3f3f?-1:ans);
        return 0;
    }
    

    https://www.luogu.org/problem/P1417

    如果没有b[i]这个属性的话就是明显的01背包问题。

    现在考虑相邻的两个物品x,y。假设现在已经耗费p的时间,那么分别列出先做x,y的代价:

    a[x]-(p+c[x])b[x]+a[y]-(p+c[x]+c[y])b[y] (①)

    a[y]-(p+c[y])b[y]+a[x]-(p+c[y]+c[x])b[x] (②)

    对这两个式子化简,得到①>②的条件是c[x]b[y]<c[y]b[x].

    发现只要满足这个条件的物品对(x,y),x在y前的代价永远更优。

    因此可以根据这个条件进行排序,之后就是简单的01背包了。

    code :

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define LL long long
    #define maxn 100001
    using namespace std;
    struct node {
        int a, b, c;
    }a[maxn];
    LL f[maxn], ans;
    int T, n, i, j;
    bool cmp(node a, node b) {
        return (LL)a.c * (LL)b.b < (LL)b.c * (LL)a.b;
    }
    int main() {
        scanf("%d%d", &T, &n);
        for (i = 0; i < n; i++)
            scanf("%d", &a[i].a);
        for (i = 0; i < n; i++)
            scanf("%d", &a[i].b);
        for (i = 0; i < n; i++)
            scanf("%d", &a[i].c);
        sort(a, a + n, cmp);
        memset(f, 255, sizeof f);
        f[0] = 0;
        for (i = 0; i < n; i++) {
            for (j = T; j >= 0; --j)
                if (f[j] != -1 && j + a[i].c <= T)
                    f[j + a[i].c] = max(f[j + a[i].c], f[j] + (LL)a[i].a - (LL)(j + a[i].c) * (LL)a[i].b);
        }
        for (i = 0; i <= T; i++)
            ans = max(ans, f[i]);
        cout << ans << endl;
    }
    
  • 相关阅读:
    组合数计算
    使用叉积判断两条直线是否相交
    关于括号的简单模拟题
    链表
    长句拆单词
    第九章 SpringCloud之Zuul路由
    第八章 SpringCloud之Feign、Hystrix结合使用
    第七章 SpringCloud之非声明式RestClient:Feign
    第六章 SpringCloud之Ribbon负载均衡
    第五章 SpringCloud之Eureka-Client使用RestTemplate实现服务之间的调用
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11864177.html
Copyright © 2011-2022 走看看