http://acm.nyist.net/JudgeOnline/problem.php?pid=737

数据很小,适合区间dp的入门

对于第[i, j]堆,无论你怎么合并,无论你先选哪两堆结合,当你把[i, j]合成一堆的那一步的时候,花费肯定就是sum[i....j]

可以用纸模拟下。

那么我们设dp[i][j]表示把i...j堆合成一堆的时候的最小花费。

比如dp[1][1] = 0。dp[1][2] = a[1] + a[2];

那么要求dp[i][j],则可以是dp[i][k] + dp[k + 1][j] + cost

注意dp的时候的顺序,因为要求dp[1][n],则需要用到dp[1][k]和dp[k][n]

你需要考虑下怎么for,才能使得子问题已经被算出,建议一开始用dfs + 记忆化做。

这里dp的顺序应该是先算出2个集合的,3个、4个、......

就是先算出dp[1][2], dp[2][3],这使得求dp[1][3]成为可能。

all dp[i][i] = 0

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string> const int maxn = + ;
int n;
int a[maxn];
int dp[maxn][maxn];
int sum[maxn];
int dfs(int be, int en) {
if (be > en) return ;
if (be == en) {
return dp[be][en] = ;
}
if (dp[be][en] != inf) return dp[be][en];
for (int k = be; k <= en; ++k) {
dp[be][k] = dfs(be, k);
dp[k + ][en] = dfs(k + , en);
assert(dp[be][k] >= );
assert(dp[k + ][en] >= );
dp[be][en] = min(dp[be][k] + dp[k + ][en] + sum[en] - sum[be - ], dp[be][en]);
// cout << dp[2][3] << endl;
}
return dp[be][en];
}
void work() {
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
sum[i] = sum[i - ] + a[i];
}
memset(dp, , sizeof dp);
// cout << dfs(1, n) << endl;
// cout << dp[2][3] << endl;
for (int k = ; k <= n - ; ++k) {
for (int i = ; i <= n - ; ++i) {
int be = i;
int en = i + k;
if (en > n) break;
dp[be][en] = inf;
for (int h = be; h <= en - ; ++h) {
dp[be][en] = min(dp[be][en], dp[be][h] + dp[h + ][en] + sum[en] - sum[be - ]);
}
}
}
printf("%d\n", dp[][n]);
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
while (scanf("%d", &n) != EOF) work();
return ;
}

平行四边形优化,其实我还不是很懂。那个证明太难了。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
int n;
const int maxn = 1e3 + ;
int dp[maxn][maxn];
int s[maxn][maxn];
int sum[maxn];
void work() {
for (int i = ; i <= n; ++i) {
int x;
scanf("%d", &x);
sum[i] = sum[i - ] + x;
dp[i][i] = ;
s[i][i] = i;
}
for (int dis = ; dis <= n - ; ++dis) {
for (int be = ; be + dis <= n; ++be) {
int en = be + dis;
dp[be][en] = inf;
int t = s[be][en];
for (int k = s[be][en - ]; k <= s[be + ][en]; ++k) {
if (k + > en) break;
if (dp[be][en] >= dp[be][k] + dp[k + ][en] + sum[en] - sum[be - ]) {
dp[be][en] = dp[be][k] + dp[k + ][en] + sum[en] - sum[be - ];
t = k;
}
}
s[be][en] = t;
}
}
cout << dp[][n] << endl;
}
int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
while (scanf("%d", &n) != EOF) work();
return ;
}

简单来说,就是设s[i][j]表示第i---j堆石子合并的时候,在第s[i][j]那里合并,是最优的。

那么可以证明的是:s[i][j - 1] <= s[i][j] <= s[i + 1][j]

那么只需要枚举里面的值就好了。

nyoj 737 石子合并(一)。区间dp的更多相关文章

  1. nyoj 737 石子合并(区间DP)

    737-石子合并(一) 内存限制:64MB 时间限制:1000ms 特判: No通过数:28 提交数:35 难度:3 题目描述:     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为 ...

  2. nyoj 737 石子合并 经典区间 dp

    石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆 ...

  3. 题解报告:NYOJ #737 石子合并(一)(区间dp)

    描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值 ...

  4. nyoj 737 石子合并 http://blog.csdn.net/wangdan11111/article/details/45032519

    http://blog.csdn.net/wangdan11111/article/details/45032519 http://acm.nyist.net/JudgeOnline/problem. ...

  5. 洛谷P1880 石子合并(区间DP)(环形DP)

    To 洛谷.1880 石子合并 题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1 ...

  6. 直线石子合并(区间DP)

    石子合并 时间限制:1000 ms  |  内存限制:65535 KB 描述有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费 ...

  7. CH5301 石子合并【区间dp】

    5301 石子合并 0x50「动态规划」例题 描述 设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300).每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆, ...

  8. zjnu 1181 石子合并(区间DP)

    Description 在操场上沿一直线排列着 n堆石子. 现要将石子有次序地合并成一堆.规定每次仅仅能选相邻的两堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分.同意在第一次合并前对调一 ...

  9. 石子合并(区间dp)

    石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描写叙述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程仅仅能每次将相邻 ...

随机推荐

  1. 20160113 JS中CheckBox如何控制全选

    //判断CheckBoxzong他的点击事件 $("#CheckBoxzong").click(function () { //取出所有class为选中的集合 var query ...

  2. IntelliJ 2016.02设置maven 阿里云加速

    修改maven 的setting.xml <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf ...

  3. 如何正确做 Web端压力测试?

    ​    ​一个完整的压力测试需要关注三个方面:如何正确产生压力.如何定位瓶颈.如何预估系统的承载能力. ​    ​(1) 如何产生压力:产生压力的方法有很多,通常可以写脚本产生压力机器人对服务器进 ...

  4. ECharts使用心得总结(二)

    Echarts使用心得总结(二) 前言: 前一段时间一直都挺忙的,各种事,也没来得及每周的总结,趁着晚上的一点时间把项目中用的Echart中常用的各种图表给抽象总结了一下,趁着周末跟大家分享一下.之前 ...

  5. Java事务处理全解析(六)—— 使用动态代理(Dynamic Proxy)完成事务

    在本系列的上一篇文章中,我们讲到了使用Template模式进行事务管理,这固然是一种很好的方法,但是不那么完美的地方在于我们依然需要在service层中编写和事务处理相关的代码,即我们需要在servi ...

  6. 使用 Sublime、WebStorm 开发 Jade

    Sublime.WebStorm (PhpStorm) 是前端开发者的得力工具,开发 Jade 也不例外. 在配置这些软件的 Jade 开发环境前,请先在系统中安装 Node.js 和 Jade : ...

  7. 极限编程之TDD

         测试驱动开发(Test-Driven Development,TDD)是通过测试定义所要开发的功能的接口,然后实现功能的开发过程. Test-Driven Development(TDD), ...

  8. ruby formatting time

    %Y%m%d => 20071119 Calendar date (basic) %F => 2007-11-19 Calendar date (extended) %Y-%m => ...

  9. RNG vs EDG | SKT vs KTB [20160826]

    G1 RNG:丽桑卓,古拉加斯,强行开团流. EDG:崔斯特,普朗克,伊莉斯游走,全球支援流,小规模团战能以多打少. G2 RNG:塔莉垭,纳尔,烬. EDG:雷克塞,艾克,劫,冲击后排. G3 RN ...

  10. do-while语句

    一.语句格式格式1:do  语句1;while (条件表达式); 格式2:do {  语句1;  语句2;  -}while (条件表达式); 语句执行过程:1.执行一遍循环体.2.求出作为循环条件的 ...