zoukankan      html  css  js  c++  java
  • 【BZOJ1190】[HNOI2007] 梦幻岛宝珠(DP水题)

    点此看题面

    大致题意: 01背包问题。其中物品个数(n≤100),背包容量和每个物品体积(≤2^{30}),且每个物品体积可以表示为(a imes 2^b(1le ale 10,ble 30))

    前言

    大概是我天天念叨总是做不出(DP)题,结果就撞见这样一道水题。

    可是,一道水题都要想好久,还挂了几发,我毕竟还是太菜。

    大致思路

    考虑题目涉及这么多(2)的幂,自然而然就想到从高到低枚举每一位(DP)

    我们假设当前枚举到第(i)位,则我们强制所有体积为(a imes 2^i)的物品都要在此时判断是否选择。

    即,我们假设(DP)到第(i)位我们最多能选体积为(j imes 2^i)的物品(此时忽略末(i)位),那么原本的大背包就被我们转化为对于每一位的小背包。

    那么这样有什么好处呢?

    由于(ale10)的,所以我们可以把(j>10n)时的情况全部归于(j=10n)!(显然吧,因为多余的容量反正用不完,不如直接舍弃)

    大致整理下思路:先枚举(i),然后通过小背包求出(g_k)表示选择体积不超过(k imes 2^i)的物品所能得到的最大代价,再枚举(j)通过刷表法(推荐使用,因为要舍弃多余容量)枚举一个(k)转移(f_{i,j})

    然后算算复杂度,枚举(i)(O(logV)),而刷表法转移(f_{i,j})(O(100n^2))的。(小背包是针对每个物品的,复杂度为(O(10n^2)),此处可以忽略)

    总复杂度是(O(100n^2logV)),看似会(T),但实际上肯定是跑不满的。就连BZOJ上都跑得飞快,你还虚什么!

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg 
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100
    #define pb push_back
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n,lim,p[35],f[35][N*10+5],g[N*10+5];
    struct data {int a,v;I data(CI x=0,CI y=0):a(x),v(y){}};vector<data> V[35];
    int main()
    {
    	RI i,j,k,x,y,t,len,ans;vector<data>::iterator it;W(scanf("%d%d",&n,&x),~n&&~x)
    	{
    		len=-1;W(x) p[++len]=x&1,x>>=1;for(i=0;i<=len;++i) V[i].clear();//把背包容量转化为二进制,并清空vector
    		for(i=1;i<=n;++i) {scanf("%d%d",&x,&y),t=0;W(!(x&1)) x>>=1,++t;V[t].pb(data(x,y));}//转化为a*2^b的形式,存入vector
    		for(lim=10*n,i=0;i<=len;++i) for(j=0;j<=lim;++j) f[i][j]=-1;//初始化清空
    		for(f[len][1]=ans=0,i=len;~i;--i)//枚举每一位
    		{
    			for(j=0;j<=lim;++j) g[j]=0;//清空
    			for(it=V[i].begin();it!=V[i].end();++it)//枚举这一位上的物品
    				for(j=lim;j>=it->a;--j) Gmax(g[j],g[j-it->a]+it->v);//小背包
    			for(j=0;j<=lim;++j) for(k=0;k<=j;++k) ~f[i][j]&&//枚举j,k刷表
    				(i&&Gmax(f[i-1][min(j-k<<1|p[i-1],lim)],f[i][j]+g[k]),Gmax(ans,f[i][j]+g[k]));//注意i=0时不再转移
    		}printf("%d
    ",ans);//输出答案
    	}return 0;
    }
    
  • 相关阅读:
    20145220&20145209&20145309信息安全系统设计基础实验报告
    20145209 《信息安全系统设计基础》第8周学习总结
    R574
    gym102219
    102222F
    luogu 1337
    luogu 2503 & bzoj 2428
    18 BJ J
    poj 1981
    101992 I
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1190.html
Copyright © 2011-2022 走看看