BZOJ 2021 [Usaco2010 Jan]Cheese Towers:dp + 贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2021

题意:

  John要建一个奶酪塔,高度最大为m。

  他有n种奶酪。第i种高度为h[i](一定是5的倍数),价值为w[i]。

  一块高度>=t的奶酪被称为大奶酪,一个奶酪如果在它上方有大奶酪(多块只算一次),它的高度就会变成原来的4/5。

  John想让他的奶酪他价值和最大,求这个最大值。

 

题解:

  方法一:

    dp + 贪心。

    贪心:如果奶酪塔中有大奶酪,则大奶酪一定放在最上面。

    (1)有大奶酪时:

      枚举放在最上面的大奶酪k。

      然后将所有奶酪的高度看作h[i]*4/5,塔的最大高度为m-h[k],跑一遍完全背包。

      每一次的答案 = 完全背包的答案 + w[k],取最大。

    (2)没大奶酪时:

      最后再跑一遍没有大奶酪的完全背包,取最大。

 

  方法二:

    分成两种情况分别处理:

      (1)塔中有大奶酪:

        dp[i]表示高度为i,有大奶酪时的最大价值。

        初始值:

          先将dp设为-INF。

          然后对于所有的大奶酪i,dp[h[i]] = max w[i]。

        然后将所有高度看作原来的4/5,跑一遍完全背包。

      (2)没有大奶酪:

        高度为原先的高度,直接跑完全背包。

    对于两种情况取最大就好。

 

AC Code(1):

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 #define MAX_N 105
 6 #define MAX_M 1005
 7 
 8 using namespace std;
 9 
10 int n,m,t;
11 int ans=0;
12 int w[MAX_N];
13 int h[MAX_N];
14 int dp[MAX_M];
15 
16 void read()
17 {
18     cin>>n>>m>>t;
19     for(int i=0;i<n;i++)
20     {
21         cin>>w[i]>>h[i];
22     }
23 }
24 
25 int cal_dp(int m,int u,int d)
26 {
27     int best=0;
28     memset(dp,0,sizeof(dp));
29     for(int i=0;i<n;i++)
30     {
31         for(int j=h[i]*u/d;j<=m;j++)
32         {
33             dp[j]=max(dp[j],dp[j-h[i]*u/d]+w[i]);
34             best=max(best,dp[j]);
35         }
36     }
37     return best;
38 }
39 
40 void solve()
41 {
42     for(int i=0;i<n;i++)
43     {
44         if(h[i]>=t) ans=max(ans,cal_dp(m-h[i],4,5)+w[i]);
45     }
46     ans=max(ans,cal_dp(m,1,1));
47 }
48 
49 void print()
50 {
51     cout<<ans<<endl;
52 }
53 
54 int main()
55 {
56     read();
57     solve();
58     print();
59 }

AC Code(2):

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 105
 5 #define MAX_M 1005
 6 
 7 using namespace std;
 8 
 9 int n,m,t;
10 int ans=0;
11 int w[MAX_N];
12 int h[MAX_N];
13 int dp[MAX_M];
14 
15 void read()
16 {
17     cin>>n>>m>>t;
18     for(int i=0;i<n;i++)
19     {
20         cin>>w[i]>>h[i];
21     }
22 }
23 
24 int cal_dp(int u,int d)
25 {
26     int best=0;
27     for(int i=0;i<n;i++)
28     {
29         for(int j=h[i]*u/d;j<=m;j++)
30         {
31             dp[j]=max(dp[j],dp[j-h[i]*u/d]+w[i]);
32             best=max(best,dp[j]);
33         }
34     }
35     return best;
36 }
37 
38 void solve()
39 {
40     memset(dp,0x80,sizeof(dp));
41     for(int i=0;i<n;i++)
42     {
43         if(h[i]>=t) dp[h[i]]=max(dp[h[i]],w[i]);
44     }
45     ans=max(ans,cal_dp(4,5));
46     memset(dp,0,sizeof(dp));
47     ans=max(ans,cal_dp(1,1));
48 }
49 
50 void print()
51 {
52     cout<<ans<<endl;
53 }
54 
55 int main()
56 {
57     read();
58     solve();
59     print();
60 }

 

转载于:https://www.cnblogs.com/Leohh/p/7625896.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值