题目大意
FJ将飞盘抛向身高为H(1 <= H <= 1,000,000,000)的Mark,但是Mark被N(2 <= N <= 20)头牛包围。牛们可以叠成一个牛塔,如果叠好后的高度大于或者等于Mark的高度,那牛们将抢到飞盘。
每头牛都一个身高,体重和耐力值三个指标。耐力指的是一头牛最大能承受的叠在他上方的牛的重量和。请计算牛们是否能够抢到飞盘。若是可以,请计算牛塔的最大稳定强度,稳定强度是指,在每头牛的耐力都可以承受的前提下,还能够在牛塔最上方添加的最大重量。(一头牛只能叠在另一头牛上方)
题目分析
观察数据范围与“三个指标”,不难看出这题是一道状压DP。
将01串作为DP的状态,表示串中位置为‘1’的这些牛叠起来所能获得的(剩下的)最大耐力值。
考虑初始化,只需将“单选一头牛”作为状态更新一下DP值即可。
考虑转移,我们现在已经有了一个状态,要在此状态的情况下再多放一头牛。若此牛的体重<=该状态的耐力值,则可更新。
转化成代码,就是
if(!(i&(1<<(j-1)))&&a[j].wei<=f[i])
f[i|(1<<(j-1))]=max(f[i|(1<<(j-1))],min(a[j].str,f[i]-a[j].wei));
再算一下该状态所有选中牛的身高和,若身高和>=H,则可更新答案。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=2e7+10; 4 5 struct Node{ 6 int hei,wei,str; 7 }a[25]; 8 9 int n,h,ans; 10 int f[MAXN]; 11 int main(){ 12 scanf("%d%d",&n,&h); 13 for(int i=1;i<=n;++i) 14 scanf("%d%d%d",&a[i].hei,&a[i].wei,&a[i].str); 15 ans=-1; 16 memset(f,-1,sizeof(f)); 17 for(int i=0;i<n;++i) 18 f[1<<i]=a[i+1].str; 19 for(int i=1;i<=(1<<n)-1;++i){ 20 for(int j=1;j<=n;++j) 21 if(!(i&(1<<(j-1)))&&a[j].wei<=f[i]) 22 f[i|(1<<(j-1))]=max(f[i|(1<<(j-1))],min(a[j].str,f[i]-a[j].wei)); 23 int res=0; 24 for(int j=1;j<=n;++j) 25 if(i&(1<<(j-1))) 26 res+=a[j].hei; 27 if(res>=h) 28 ans=max(ans,f[i]); 29 } 30 if(ans==-1) printf("Mark is too tall "); 31 else printf("%d ",ans); 32 return 0; 33 }