USACO 2014 December Contest Gold T1: Guard Mark

题目大意

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\n");
31     else printf("%d\n",ans);
32     return 0;
33 } 

 

posted @ 2019-07-19 11:45  LI_dox  阅读(204)  评论(0编辑  收藏  举报