卧薪尝胆,厚积薄发。
USACO2014DEC GOLD 后卫马克
Date: Sat Sep 08 13:56:17 CST 2018
In Category:
NoCategory
Description:
$N$
头牛每头牛有自己的高度,自身重量及承受重量。 选出一些牛来叠成一堆。问是否可以到一个高度为
$H$
的值。如果能到最大化还可以在上面继续放的重量。
$1\le n \le 20$
Solution:
做法一:贪心。
按照
$w+s$
排序按从大到小的顺序叠放,
$dfs$
枚举
$2^n$
种方案再
$check$
。
证明:设叠的重量前缀和为
$W$
,第一种方案最终的结果是
$\min(s_1-W-w_2,s_2-W)$
,第二种方案最终结果是
$\min(s_2-W-w_1,s_1-W)$
,因为
$s_1+w_1>s_2+w_2$
,所以
$s_1-W-w_2>s_2-W-w_1$
,。
口胡没有代码。
做法二:状压
$DP$
。
设
$f[S]$
表示当选的牛的集合为
$S$
时的最大承受重量,因为集合已知所以高度也可以计算,那么转移为
$f[S\cup \{i\}]=\max(\min(f[S]-w[i],s[i]))$
,相当于每次把新加的牛放在最上面。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 21
int h[MAXN],w[MAXN],s[MAXN];
int f[1 << MAXN],g[1 << MAXN];
int main()
{
scanf("%d%d",&n,&m);
int sum = 0;
for(int i = 1;i <= n;++i)scanf("%d%d%d",&h[i],&w[i],&s[i]);
for(int i = 1;i <= n;++i)sum += h[i];
int tot = (1 << n) - 1;
int ans = -1;
f[0] = 0x3f3f3f3f;
for(int b = 0;b <= tot;++b)
{
for(int i = 1;i <= n;++i)
{
if(!(b & (1 << (i - 1))))
{
if(f[b] >= w[i])
{
f[b | (1 << (i - 1))] = max(f[b | (1 << (i - 1))],min(f[b] - w[i],s[i]));
g[b | (1 << (i - 1))] = g[b] + h[i];
}
}
}
if(b != 0 && g[b] >= m)ans = max(ans,f[b]);
}
if(ans == -1)puts("Mark is too tall");
else cout << ans << endl;
return 0;
}
In tag:
DP-状压DP
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡