NIOP1995 石子合并(区间DP)

本文详细解析了石子合并问题的算法实现,通过状态转移方程优化了问题求解过程,利用四边形不等式将复杂度由O(n^3)降低至O(n^2),并附带完整代码示例。

状态转移方程在代码中标出

本题注意是圆形,所以之前要预先处理一下s数组。处理之后总长度为2*n-1.第一个合并的起点有n个,所以总的方案数是n

注释在代码中标出

http://www.rqnoj.cn/problem/490

 

石子合并问题推荐几篇很好的文章

http://blog.youkuaiyun.com/acdreamers/article/details/18039073

http://blog.youkuaiyun.com/bnmjmz/article/details/41308919

注意四边形不等式优化,可以把n^3优化到n^2

 

 1 //#pragma comment(linker, "/STACK:167772160")//手动扩栈~~~~hdu 用c++交
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<queue>
 7 #include<stack>
 8 #include<cmath>
 9 #include<set>
10 #include<algorithm>
11 #include<vector>
12 // #include<malloc.h>
13 using namespace std;
14 #define clc(a,b) memset(a,b,sizeof(a))
15 #define LL long long
16 const int Inf = 0x3f3f3f3f;
17 const double eps = 1e-5;
18 const double pi = acos(-1);
19 // inline int r(){
20 //     int x=0,f=1;char ch=getchar();
21 //     while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
22 //     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
23 //     return x*f;
24 // }
25 const int Times = 10;
26 const int N = 5500;
27 int s[210],d[210][210],p[210][210],a[210];//d/p表示i到j的最小/大花费
28 int main(){
29     int n;
30     int m;
31     s[0]=0;
32     while(~scanf("%d",&n)){
33         clc(d,0);
34         clc(p,0);
35         for(int i=1;i<=n;i++){
36             scanf("%d",&a[i]);
37             s[i]=s[i-1]+a[i];
38         }
39         for(int i=1;i<n;i++){
40             s[i+n]=s[n+i-1]+a[i];
41         }
42         m=n,n=n*2-1;
43         int j,tem1,tem2;
44         for(int r=2;r<=n;r++){//枚举i到j的长度
45             for(int i=1;i<=n-r+1;i++){//i起始坐标,j表示当前枚举的终点坐标
46                  j=i+r-1,tem1=Inf,tem2=0;
47                  for(int k=i;k<j;k++){
48                     tem1=min(tem1,d[i][k]+d[k+1][j]+s[j]-s[i-1]);
49                     tem2=max(tem2,p[i][k]+p[k+1][j]+s[j]-s[i-1]);
50                  }
51                  d[i][j]=tem1;
52                  p[i][j]=tem2;
53             }
54         }
55         tem1=Inf,tem2=0;
56         for(int i=1;i<=m;i++){//合并长度从1到m
57             if(tem1>d[i][m+i-1]) tem1=d[i][m+i-1];
58             if(tem2<p[i][m+i-1]) tem2=p[i][m+i-1];
59         }
60         if(n==1) tem1=tem2=a[1];
61         printf("%d\n%d\n",tem1,tem2);
62     }
63     return 0;
64 }
View Code

 

转载于:https://www.cnblogs.com/ITUPC/p/5466535.html

### NOIP2008 提高组 概述 NOIP2008(全国青少年信息学奥林匹克联赛)提高组的比赛吸引了众多选手参与。该赛事旨在考察参赛者在算法设计、编程实现等方面的能力。 ### 题目概述 比赛共设有四道题目,涵盖了不同的知识点和技术要点: 1. **传纸条** 这是一道经典的动态规划问题,要求计算从矩阵一角到另一角传递消息的最大价值路径[^3]。 2. **双栈排序** 此题涉及数据结构的应用,特别是栈的操作及其组合使用来完成特定序列的排序任务[^4]。 3. **笨小猴** 主要测试字符串处理能力以及简单的贪心策略应用,在给定条件下寻找最优解方案[^5]。 4. **火柴棒等式** 属于数论范畴,通过调整算术表达式的构成部分使得最终结果满足一定条件下的最大可能性[^6]。 ### 解题思路分析 针对上述各题目的解决方案通常会经历如下思考过程: 对于《传纸条》这类最优化求解类问题,可以采用二维数组记录状态转移方程的方式来进行高效解答;而对于像《双栈排序》这样的结构性难题,则需充分理解并灵活运用所掌握的数据结构特性,比如利用两个栈模拟队列操作从而达到预期效果;至于《笨小猴》,则更多依赖于对输入模式的理解与快速匹配技巧;最后,《火柴棒等式》考验的是考生们如何巧妙转换视角看待传统数学运算规则,并据此构建合理的枚举框架以穷尽所有可行选项。 ```cpp // 示例代码片段展示一种可能用于解决“传纸条”的方法 #include <iostream> using namespace std; const int MAXN = 50 + 5; int dp[MAXN][MAXN], a[MAXN][MAXN]; int main() { // 初始化及读入省略... for (int i = n; i >= 1; --i) { for (int j = m; j >= 1; --j) { dp[i][j] = max(dp[i+1][j],dp[i][j+1]) + a[i][j]; } } cout << "The maximum value is:" << endl; cout << dp[1][1]<<endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值