• BZOJ 1190: [HNOI2007]梦幻岛宝珠 背包DP


    题意

    大背包问题
    物品重量可写成a*2^b的形式(1<=a<=10,0<=b<=30)

    (实测int能过,就没写longlong)

    题解1

    直接背包肯定TLE+MLE

    考虑到每个weight都能写成a*2^b的形式,显然我们要按照b分层来进行背包

    令f[i][j]表示有j*2^i+(w&(1<<i)-1)的空间时的最大价值

    首先每层内部先做一个01背包,因为a<=10,n<=100,所以容量最大为1000

    然后层与层之间再转移

    从大到小枚举j 转移方程为f[i][j]=max{f[i][j],f[i][j-k]+f[i-1][min(k*2+((w>>i-1)&1),1000)]}

    转自PoPoQQQ的博客

    CODE1

    时间复杂度O(1001000+3010001000)O(100*1000+30*1000*1000)

    慢。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int MAXN = 105;
    const int MAXM = 1000;
    const int LOG = 30;
    int n, W, f[LOG+5][MAXM+5];
    
    int main () {
    	while(scanf("%d%d", &n, &W)) {
    		if(n == -1 || W == -1) return 0;
    		memset(f, 0, sizeof f);
    		for(int i = 1, a, b, val; i <= n; ++i) {
    			b = 0;
    			scanf("%d%d", &a, &val);
    			while(b <= 30 && !(a&1)) ++b, a>>=1;
    			for(int j = MAXM; j >= a; --j)
    				f[b][j] = max(f[b][j], f[b][j-a] + val);
    		}
    		int ans = 0;
    		for(int i = 0; i <= min(MAXM, W); ++i)
    			ans = max(ans, f[0][i]);
    		for(int i = 1; i <= LOG && (1<<i) <= W; ++i)
    			for(int j = min(MAXM, W>>i); j >= 0; --j) {
    				for(int k = 0; k <= j; ++k)
    					f[i][j] = max(f[i][j], f[i][j-k] + f[i-1][min(MAXM, (k<<1)+((W>>i-1)&1))]);
    				ans = max(ans, f[i][j]);
    			}
    		printf("%d
    ", ans);
    	}
    }
    

    题解2

    按b从大到小DP,继承上一层的答案后直接01背包。因为是从高位到低位,不会对后面有影响。

    此处状态定义为 f[i][j]f[i][j]表示可用容量为j2ij*2^i的最大价值。

    然后每次减小a10ale 10,一定不会减小超过10001000,每一层只开10001000就行了。

    CODE2

    时间复杂度O(1000100+301000)O(1000*100+30*1000)

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 105, MAXM = 1000, LOG = 30;
    int n, W, f[LOG+5][MAXM+5];
    vector<pair<int,int> >vec[MAXN];
    int main () {
    	while(scanf("%d%d", &n, &W)) {
    		if(n == -1 || W == -1) return 0;
    		for(int i = 0; i <= LOG; ++i) vec[i].clear();
    		for(int i = 1, a, b, val; i <= n; ++i) {
    			b = 0; scanf("%d%d", &a, &val);
    			while(b <= 30 && !(a&1)) ++b, a>>=1;
    			vec[b].push_back(pair<int,int>(a, val));
    		}
    		memset(f, -0x3f, sizeof f); f[LOG+1][0] = 0;
    		for(int i = LOG; i >= 0; --i) {
    			for(int j = 0; j <= MAXM; ++j)
    				f[i][min(MAXM, (j<<1)|((W>>i)&1))] = max(f[i][min(MAXM, (j<<1)|((W>>i)&1))], f[i+1][j]);
    			for(int siz = vec[i].size(), k = 0; k < siz; ++k)
    				for(int j = 0; j <= MAXM - vec[i][k].first; ++j)
    					f[i][j] = max(f[i][j], f[i][min(MAXM, j+vec[i][k].first)] + vec[i][k].second);
    		}
    		printf("%d
    ", *max_element(f[0], f[0] + 1000 + 1));
    	}
    }
    
  • 相关阅读:
    MySQL存储写入性能严重抖动分析
    关于MySQL的commit非规律性失败案例的深入分析
    MySQL存储写入速度慢分析
    MySQL缓存之Qcache与buffer pool对比
    SQL执行过程中的性能负载点
    关于MySQL用户会话及连接线程
    如何查询、修改参数状态值
    genymotion 前端调试
    name是个特殊的变量名吗
    background-size 导致的背景不居中问题
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039215.html
Copyright © 2020-2023  润新知