3/10 动规回顾

3/10 动规回顾

由一道完全背包和多重背包结合的洛谷题引入

P1833 樱花

key code

const int N=1e4+10;
int n,m;
int a[N],b[N],c[N];
int dp[10010];
void solve(){
	//try it again.
	// mem1(dp);
	int begin=0;
	int end=0;
	int x;char t;
	cin>>x>>t;
	begin+=x*60;cin>>x;
	begin+=x;
	cin>>x>>t;
	end+=x*60;cin>>x;
	end+=x;
	int lenth=end-begin;
	m=lenth;
	// cout<<lenth<<endl;
	dp[0]=0;
	cin>>n;
	up(1,n){cin>>a[o]>>b[o]>>c[o];}
	up(1,n){
		if(c[o]==0){
			fup(j,a[o],m){
				dp[j]=max(dp[j-a[o]]+b[o],dp[j]);
			}
		}
		else{
			for(int k=1;k<=c[o];k++){
				for(int j=m;j>=a[o];j--){
					dp[j]=max(dp[j],dp[j-a[o]]+b[o]);
				}
			}
		}
	}
	cout<<dp[m]<<endl;
}

回顾一下背包

  1. 01背包

    1. 只能选一次,遍历方向与贡献的方向相反
  2. 完全背包

    1. 可以选无数次,遍历方向与贡献方向相同
  3. 多重背包

    1. 可以选择多次,遍历方向与贡献方向相同且有次数限制

    2. 一个一个的枚举会浪费大量的时间,我们可以通过枚举二进制状态来压缩时间

    3. 二进制拆分的板子

      	int tv,tw,s;
      	cin>>tv>>tw>>s;
      	int k=1;
      	while(s>=k){
      		v[++cnt]=tv*k;
      		w[cnt]=tw*k;
      		s-=k;
      		k*=2;
      	}
      	if(s>0){
      		v[++cnt]=tv*s;
      		w[cnt]=tw*s;
      	}
  1. 分组背包

    1. 背板子即可

    2. 板子:

      	cin >> n >> m;
          for (int i = 1; i <= n; i ++ ){
              cin >> s[i];
              for (int j = 0; j < s[i]; j ++ )
                  cin >> v[i][j] >> w[i][j];
          }
          for (int i = 1; i <= n; i ++ )
              for (int j = m; j >= 0; j -- )
                  for (int k = 0; k < s[i]; k ++ )
                      if (v[i][k] <= j)
                          f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);
          cout << f[m] << endl;
posted @ 2023-03-12 00:33  liangqianxing  阅读(55)  评论(0)    收藏  举报