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;
    }
    
  • 相关阅读:
    Microsoft Enterprise Library 5.0 系列(二) Cryptography Application Block (初级)
    Microsoft Enterprise Library 5.0 系列(五) Data Access Application Block
    Microsoft Enterprise Library 5.0 系列(八) Unity Dependency Injection and Interception
    Microsoft Enterprise Library 5.0 系列(九) Policy Injection Application Block
    Microsoft Enterprise Library 5.0 系列(三) Validation Application Block (高级)
    软件研发打油诗祝大家节日快乐
    从挖井的故事中想到开发管理中最容易忽视的几个简单道理
    ITIL管理思想的执行工具发布
    管理类软件设计“渔”之演化
    20070926日下午工作流与ITILQQ群 事件管理 讨论聊天记录
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11864177.html
Copyright © 2011-2022 走看看