nyoj 737 石子合并(一)。区间dp
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的更多相关文章
- nyoj 737 石子合并(区间DP)
737-石子合并(一) 内存限制:64MB 时间限制:1000ms 特判: No通过数:28 提交数:35 难度:3 题目描述: 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为 ...
- nyoj 737 石子合并 经典区间 dp
石子合并(一) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆 ...
- 题解报告:NYOJ #737 石子合并(一)(区间dp)
描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值 ...
- nyoj 737 石子合并 http://blog.csdn.net/wangdan11111/article/details/45032519
http://blog.csdn.net/wangdan11111/article/details/45032519 http://acm.nyist.net/JudgeOnline/problem. ...
- 洛谷P1880 石子合并(区间DP)(环形DP)
To 洛谷.1880 石子合并 题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1 ...
- 直线石子合并(区间DP)
石子合并 时间限制:1000 ms | 内存限制:65535 KB 描述有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费 ...
- CH5301 石子合并【区间dp】
5301 石子合并 0x50「动态规划」例题 描述 设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300).每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆, ...
- zjnu 1181 石子合并(区间DP)
Description 在操场上沿一直线排列着 n堆石子. 现要将石子有次序地合并成一堆.规定每次仅仅能选相邻的两堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分.同意在第一次合并前对调一 ...
- 石子合并(区间dp)
石子合并(一) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描写叙述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程仅仅能每次将相邻 ...
随机推荐
- JSBinding / Home
Description JSBinding is a tool enabling you to run actual javascript in Unity3D. It contains Mozill ...
- Java--RuntimeException(运行时异常)
[转载自]:http://blog.csdn.net/qq7342272/article/details/7940741 java运行时异常是可能在java虚拟机正常工作时抛出的异常. java提供了 ...
- JdbcUtils 系列1
1.开发前准备 创建java pro为dbutils_1,没有lib目录,建一个即可 /dbutils_1/lib/mysql-connector-java-5.0.8-bin.jar 数据库搭建c3 ...
- Winform中调用js函数
var wb = new WebBrowser(); wb.AllowNavigation = true; wb.ScriptErrorsSuppressed = false; wb.Navigate ...
- linux网络虚拟化
图解几个与Linux网络虚拟化相关的虚拟网卡-VETH/MACVLAN/MACVTAP/IPVLAN http://smilejay.com/2012/08/qemu-kvm-networking-m ...
- nodejs项目在webstorm里进行debug的设定
菜单 > Run > Edit Configurations... 菜单 > Run > Debug... 菜单 > Run > Edit Configuratio ...
- sql查看数据字典(表结构)
SELECT (case when a.colorder=1 then d.name else null end) 表名, a.colorder 字段序号,a.name 字段名, (case when ...
- 大师教你<部落冲突>如何切换账号
前提申请两个谷歌账号,账号一和账号二,想要切换账号,只需清除部落冲突在手机上的数据即可.详情请看下文! 1. 第一次登陆,进入游戏后 2. 没有谷歌商店的童鞋,下载谷歌安装器(一键修复)以及VPNFQ ...
- HackerRank "Larry's Array"
I caught the sparkle in my mind and got AC1 ! It is a great great experience ! So the basic idea: pe ...
- 闲谈Tomcat性能优化
Tomcat在各位JavaWeb从业者常常就是默认的开发环境,但是Tomcat的默认配置作为生产环境,尤其是内存和线程的配置,默认都很低,容易成为性能瓶颈. 幸好Tomcat还有很多的提升空间.下文介 ...