luoguP1437 [HNOI2004]敲砖块(dp)
来源:互联网 发布:网络的负面影响规点 编辑:程序博客网 时间:2024/05/22 03:23
题目背景
无
题目描述
在一个凹槽中放置了 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 52 2 3 48 2 72 349
输出样例#1: 复制
19
分析:
ZYXZYXZYX在我做这道题之前,告诉我这道题额转移要斜着来
一开始我还不大理解,当我看到输入数据的时候,我就尝试着把数据旋转90°
2 2 3 4
8 2 7
2 3
49
—>
4
3 7
2 2 3
2 8 2 49
这样有什么好处呢:
题目中的限制:敲掉一个就必须把上面的砖块都敲掉
就变成了每次必须选择一个前缀加入贡献,
同时要满足当前前缀的最右端点不超过上一行我们选择的前缀的最右端点+1
(请仔细品读这句不像人话的人话)
于是我就开心的设计状态:f[m][i][j]
表示当前选择了m块,最后选择的前缀是第i行的前j个
然后就A了。。。猝不及防
tip
注意f数组的初始化为-INF,这样可以解决上一行不选的问题
循环的边界需要注意
//这里写代码片#include<cstdio>#include<cstring>#include<iostream>using namespace std;int a[51][51],sum[51][51];int n,m;int f[1500][51][51]; void doit(){ memset(f,128,sizeof(f)); //注意初始值 f[1][1][1]=sum[1][1]; f[0][1][0]=0; int i,j,k,c; for (i=1;i<n;i++) for (j=0;j<=i;j++) //上一行可以一块都不选 for (k=0;k<=j+1;k++) for (c=0;c<=m-k;c++) //总数不能超过m { f[c+k][i+1][k]=max(f[c+k][i+1][k],f[c][i][j]+sum[i+1][k]); } }int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=n;j>=i;j--) scanf("%d",&a[j][i]); memset(sum,0,sizeof(sum)); for (int i=1;i<=n;i++) for (int j=1;j<=i;j++) sum[i][j]=sum[i][j-1]+a[i][j]; doit(); int ans=0; for (int i=1;i<=n;i++) for (int j=1;j<=i;j++) ans=max(ans,f[m][i][j]); printf("%d\n",ans); return 0;}
luogu上的最优解是坐在后面的澍神(yss)不久之前创造的
思路是一样的,优化在于滚动数组以及清奇的码风
//这里写代码片#include<bits/stdc++.h>#define R(i) i = read()#define FUCK cout << "FUCK\n"#define D(i) cout << i << endlusing namespace std;const int N = 55;int f[2][N][N * N / 2], g[2][N][N * N / 2], a[N][N], sum[N][N];inline int read() { int x = 0; char c = getchar(); while(c < 48 || c > 57) c = getchar(); while(c >= 48 && c <= 57) x = x * 10 + c - 48, c = getchar(); return x;} inline int max(int x, int y) { return x > y ? x : y;}int main() {// freopen("1.in", "r", stdin); int n, m, ans = 0; R(n), R(m); for(int i = 1; i <= n; i++) for(int j = 1; j <= n + 1 - i; j++) R(a[i][j]); for(int j = 1; j <= n; j++) for(int i = 1; i <= n + 1 - j; i++) sum[i][j] = sum[i - 1][j] + a[i][j]; g[(n + 1) & 1][0][0] = 0; int t; for(int j = n; j >= 1; j--) { t = j & 1; memset(f[t], 0, sizeof(f[t])); memset(g[t], -127 / 3, sizeof(g[t])); for(int i = 0; i <= n + 1 - j; i++) { int lim = (n - j) * (n + 1 - j) / 2 + i; for(int k = i; k <= min(lim, m); k++) f[t][i][k] = max(f[t][i][k], g[t ^ 1][(i - 1) < 0 ? 0 : i - 1][k - i] + sum[i][j]), ans = max(ans, f[t][i][k]); } for(int i = n + 1 - j; i >= 0; i--) { int lim = (n - j) * (n + 1 - j) / 2 + n + 1 - j; for(int k = i; k <= min(lim, m); k++) g[t][i][k] = max(f[t][i][k], g[t][i + 1][k]); } } cout << ans; return 0;}
阅读全文
0 0
- luoguP1437 [HNOI2004]敲砖块(dp)
- DP——Luogu1437 [HNOI2004]敲砖块
- 神奇DP [HNOI2004] 打砖块
- [HNOI2004]敲砖块 (洛谷1437)
- 【HNOI2004】敲砖块
- [HNOI2004]敲砖块
- dp——洛谷P1437 [HNOI2004]敲砖块
- 【HNOI2004】 敲砖块 动态规划
- 洛谷 P1437 [HNOI2004]敲砖块
- 洛谷 P1437 [HNOI2004]敲砖块
- 洛谷 P1437 [HNOI2004]敲砖块
- 敲砖块(dp )
- HNOI2004 打砖块
- 【HNOI2004】打砖块
- [noip模拟赛]敲砖块(dp)
- smoj1710:砖块II (dp套dp)
- 【HNOI2004】邮递员 (插头DP一条回路)
- bzoj 1207: [HNOI2004]打鼹鼠 (DP)
- net.sf.json.JSONException: java.lang.reflect.InvocationTargetException错误的原因与解决方法?
- 游戏人工智能开发之6种决策方法
- Can't use Subversion command line client:svn
- JAVA 结构体sort举例
- linux下练习正则表达式
- luoguP1437 [HNOI2004]敲砖块(dp)
- 移植libffi到SylixOS
- 添加 排序
- 排jar包的依赖冲突的方法
- Spring Cloud之服务注册与发现Eureka【Dalston.SR4版】
- banner实现无线轮播
- luogu P3088 [USACO13NOV]Crowded Cows
- java基础练习-统计字符串中每个字符出现的次数
- java中内部类详解