[HNOI2004]敲砖块

题目描述

在一个凹槽中放置了 n 层砖块、最上面的一层有n 块砖,从上到下每层依次减少一块砖。每块砖

都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示。

14 15  4  3  23
 33  33 76  2
   2   13 11
     22 23
       31

如果你想敲掉第 i 层的第j 块砖的话,若i=1,你可以直接敲掉它;若i>1,则你必须先敲掉第

i-1 层的第j 和第j+1 块砖。

你现在可以敲掉最多 m 块砖,求得分最多能有多少。

输入输出格式

输入格式:

输入文件的第一行为两个正整数 n 和m;接下来n 行,描述这n 层砖块上的分值a[i][j],满足

0≤a[i][j]≤100。

对于 100%的数据,满足1≤n≤50,1≤m≤n*(n+1)/2;

输出格式:

输出文件仅一行为一个正整数,表示被敲掉砖块的最大价值总和。

输入输出样例

输入样例#1:
4 5
2 2 3 4
8 2 7
2 3
49
输出样例#1:
19


把三角形旋转,变成

4

3 7

2 2 3

2 8 2 49

这样条件就变成了取(i,j)时,要取(i,1~j)和(i-1,1~j-1)

因此可以从右到左,一列一列的转移状态。

F[i][j][k]表示第i列,第j行的数被取,且共取k个数的最优方案。

F[i][j][k]=max(F[i+1][x][k-j])+sigma(a[1][i]…a[j][i]).(x>=j-1).

注意m的数据范围,较原题修改过。

时间为O(n^3*m) 这样已经做完了,但仍可以优化。

可以用s[j][i]前缀和优化掉sigma(a[1][i]…a[j][i])

用g[i][j][k]表示max(f[i][j][k]..f[i][n-i+1][k])

这样时间为O(n^2*m),空间O(n^2*m),效率极高,已无法继续优化。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 int a[51][51],n,m,f[51][51][2501],ans;
 7 int main()
 8 {int i,j,k,l;
 9     cin>>n>>m;
10     for (i=1;i<=n;i++)
11     {
12         for (j=n;j>=i;j--)
13          scanf("%d",&a[j][i]);
14     }
15     for (i=1;i<=n;i++)
16     {
17         for (j=1;j<=i;j++)
18         a[i][j]+=a[i][j-1];
19     }
20     for (i=1;i<=n;i++)
21     {
22         for (j=0;j<=i;j++)
23         {
24             for (k=(j+1)*j/2;k<=i*(i-1)/2+j;k++)
25             {
26                 for (l=j-1;l<i;l++)
27                  f[i][j][k]=max(f[i][j][k],f[i-1][l][k-j]+a[i][j]);
28             }
29         }
30     }
31     for (i=1;i<=n;i++)
32     for (j=0;j<=i;j++)
33      ans=max(ans,f[i][j][m]);
34     cout<<ans;
35 return 0;
36 }

 

posted @ 2017-08-06 14:00  Z-Y-Y-S  阅读(525)  评论(0编辑  收藏  举报