动态规划

动态规划:圆形石子合并问题

烈酒焚心 提交于 2019-12-02 20:22:21
为什么80%的码农都做不了架构师?>>> 问题描述: 在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。 规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。 试设计一个算法,计算出将n堆石子合并成一堆的最小得分。 import java.util.Scanner; public class Test { /* * 圆形石子问题动态规划解法。 * p[i] 表示第i堆石子的个数。 * sum[i][j] 表示从第i堆石子开始,长度为j的各堆石子的总分。 * dp[i][j] 表示从第i堆石子开始,长度为j的各堆石子的最优组合的分数,即分数最小。 * 其中dp[i][1]=0; * dp[i][j]=min(dp[i][k]+dp[(i+k-1)%n+1][j-k]+sum[i][j]),其中1<=k<j */ public static void main(String[] args){ Scanner reader = new Scanner(System.in); int n = reader.nextInt(); int[] p = new int[n+1]; int[][] sum = new int[n+1][n+1]; int[][] dp = new int[n+1][n+1]; for(int i=1;i<=n;i+

深入理解合并类动态规划——合并石子

冷暖自知 提交于 2019-12-02 20:07:18
【题目描述】 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分. 【输入格式】 数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数. 【输出格式】 输出共2行,第1行为最小得分,第2行为最大得分 【样例输入】 4 4 4 5 9 【样例输出】 43 54 #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #define h 4001 using namespace std; /* 第一种考虑思维: f[i][j]意思是从堆i到堆j合并花费的最小值。 合并石子是一个合并类的动态规划问题,f[i][j]合并费用最小,则看是否存在k使得f[i][k]+f[k+1][j]+sum[i][j]更小 (其中sum[i][j]表示石子i堆到j堆得数量之和,它表示把已合并的[i][k]与[k+1][j]两堆再合并的花费) 这样的处理方法,就类似于最短路径问题了,欲求[i][j]之间的最短路,看是否能存在中间连接点k使得[i][k]+[k][j]路程更短的问题 动归方程: f[i][j]=min(f

C++石子合并问题(动态规划)

可紊 提交于 2019-12-02 20:03:51
一、问题描述 问题描述:在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选择相邻的两堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。 算法设计:试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。 样例输入:由input.txt提供输入数据 样例输出:输出数据保存到output.txt 输入文件示例:input.txt 4 4 4 5 9 输出文件示例:output.txt 43 54 二、 问题分析 (以求最大得分为例) (1).先看石子排成一排的问题 石子数量如下: 4 4 5 9 求其最大的合并值 m[i][j]=m[i][k]+m[k+1][j]+getsum(i,j); 这里的i,j是指石子的下标,第i堆,第j堆。m[i][j]表示合并第i堆到第j堆的石子的最大得分。其中getsum=a[i]+...+a[j];表示加上合并后总的石子数量。 (2).如果石子是按环形排列 环形排列存在的问题: 合并方向不明确的 问题,比如m[1][3]: 在线性问题中,它表示的是讲a[1],a[2],a[3]三堆石子合并起来,然而在环形排列中我们它存在两种情况。一是:合并a[1],a[2],a[3];二是:合并a[3],a[4],a[1]。 解决方案,更改表示方法,比如m[i][j]: 它表示的是合并从第i堆开始的往下j堆石子,总共j

石子合并 动态规划(环形)

℡╲_俬逩灬. 提交于 2019-12-02 20:01:29
1、问题描述:问题来源 NWPU noj 1148 在一个 圆形操场 的四周摆放着n堆石子(n<= 100),现要将石子有次序地合并成一堆。规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。编一程序,读入石子堆数n及每堆的石子数(<=20)。选择一种合并石子的方案,使得做n-1次合并,得分的总和最小; 比如有4堆石子:44 5 9 则最佳合并方案如下: 4 4 5 9 score: 0 8 5 9 score: 8 13 9 score: 8 + 13 = 21 22 score: 8 + 13 + 22 = 43 2、输入 可能有多组测试数据。 当输入n=0时结束! 第一行为石子堆数n(1<=n<=100);第二行为n堆的石子每堆的石子数,每两个数之间用一个空格分隔。 3、输出 合并的最小得分,每个结果一行。 4、问题解析 这个问题和直线型的区别在于最后一堆和第一堆也是相邻的,可以把圆形转换成直线型,把问题扩展为2n-1堆石子,举个例子,如果环形石子堆是4 4 5 9,那么转换成直线型就变成了 4 4 5 9 4 4 5,所以最终就不是计算 0~n-1了,而是在 0~n-1,1-n,2-n+1,...,n-1~2n-2中选择最小的。计算方法和直线型的相同。 5、代码如下:(已经提交过验证) #include<iostream> #include

动态规划石子合并问题

限于喜欢 提交于 2019-12-02 19:58:59
问题描述:在一个圆形操场的四周摆放着n堆石子,现要将石子有次序的合并成一堆。每次只能选择相邻的2堆石子合并成新的一堆,并将新的一对石子数记为该次合并的得分。 求 最小值和最大值 in: 4 4 4 5 9 out: 43 54 1.首先考虑 石子是环形摆放 所以可以 将数组存放成 4 4 5 9 4 4 5 2.然后从局部最优求到全局最优其中采用2个数组来储存 运算过程用到的数据 m**用来储存合并后石子的数量 result**用来储存得分 void maxdynamic(int *p, int n, int **m,int**result) {//n为数组个数 for (int i = 0; i < 2*n-1; i++) { m[i][i] = p[i];//m存放没堆石头的个数 result[i][i] = 0;//存放分数 } for (int r = 2; r <= n*2-r; r++)//这里 r<n*2-r 可以改成 r<n 减少运算次数 for (int i = 0; i <n; i++) { int j = i + r - 1;//左值:i 右值:j 宽度:r for (int k = i; k < j; k++) {//假设k为断开的地方,计算result 和m int t = m[i][k] + m[k + 1][j]+result[i][k]+result

动态规划之石子合并

落爺英雄遲暮 提交于 2019-12-02 19:58:47
1、问题 ( 1 )路边玩法 有 n 堆石子堆放在路边,现要将石子有序地合并成一堆,规定每次只能移动相邻的两堆石子合并,合并花费为新合成的一堆石子的数量。求将这 N 堆石子合并成一堆的总花费(最小或最大)。 2、分析 ( 1 )建立最优值递归式 设 Min [i][j] 代表从第 i 堆石子到第 j 堆石子合并的最小花费, Min [i][k] 代表从第 i 堆石子到第 k 堆石子合并的最小花费,Min[k+1][j] 代表从第 k+1 堆石子到第 j 堆石子合并的最小花费, w ( i , j )代表从 i 堆到 j 堆的石子数量之和。列出递归式: Min [ i ][ j ] = 0 (i = j) Min [ i ][ j ] = min ( Min [ i ][ k ] + Min [ k + 1][ j ] + w ( i , j )) , i < j( i ≤ k < j) Max [i][j] 代表从第 i 堆石子到第 j 堆石子合并的最大花费,Max [i][k] 代表从第 i 堆 石子到第 k 堆石子合并的最大花费,Max [k+1][j] 代表从第 k+1 堆石子到第 j 堆石子合并的最大花费, w ( i , j )代表从 i 堆到 j 堆的石子数量之和。列出递归式: Max [ i ][ j ] = 0 (i = j) Max [ i ][ j ] =max

[CF837D]Round Subset_动态规划

北城余情 提交于 2019-12-02 19:43:49
Round Subset 题目链接: http://codeforces.com/problemset/problem/837/D 数据范围 :略。 题解 : $dp$比较显然。 但是卡空间,有两种方法: 第一种是滚动数组,第二种是反向枚举。 这两种都可以达到:当前更新需要的数组位置仍然是上个版本的数组。 来源: https://www.cnblogs.com/ShuraK/p/11761201.html

CF837D Round Subset 动态规划

﹥>﹥吖頭↗ 提交于 2019-12-02 18:54:31
开始的时候数据范围算错了~ 我以为整个序列 2 和 5 的个数都不超过 70 ~ 一个非常水的 dp code: #include <bits/stdc++.h> #define M 75 #define N 201 #define LL long long using namespace std; void setIO(string s) { string in=s+".in"; string out=s+".out"; freopen(in.c_str(),"r",stdin); freopen(out.c_str(),"w",stdout); } int f[N][6800]; struct node { int t2,t5; }t[N]; int main() { // setIO("dynamic-programming"); int i,j,n,k; scanf("%d%d",&n,&k); memset(f,-0x3f,sizeof(f)); f[0][0]=0; for(i=1;i<=n;++i) { LL x; scanf("%lld",&x); while(x%2==0) ++t[i].t2,x/=2; while(x%5==0) ++t[i].t5,x/=5; } for(i=1;i<=n;++i) { for(j=i;j>=1;--j) { for(int

数据结构与算法学习大纲

限于喜欢 提交于 2019-12-02 18:17:11
  [TOC]      学习一门语言就练练下面的数据结构和算法.      01链表      1. 链表的必备知识要点(包括基础知识、刷题中使用的STL等知识)      2. 链表逆序(LeetCode 92,206. Reverse Linked List 1,2)      3. 求两个链表的交点(LeetCode 160. Intersection of Two Linked Lists)      4. 链表的节点交换(LeetCode 24. Swap Nodes in Pairs)      5. 链表求环(LeetCode 141,142. Linked List Cycle 1,2)      6. 链表重新构造(LeetCode 86. Partition List)      7. 复杂的链表复制(LeetCode 138. Copy List with Random Pointer)      8. 排序链表合并(2个与多个) (LeetCode 21,23 Merge Two(k) Sorted ListsLeetCode)      02栈、队列、堆      1. 栈、队列知识要点与实现(数组、链表)      2. 使用队列实现栈(LeetCode 232. Implement Queue using Stacks)      3.

动态规划训练之十八

自闭症网瘾萝莉.ら 提交于 2019-12-02 17:58:57
https://www.luogu.org/problem/P2868 分析: 明显的01分数规划 求最优比率环 用dfs版的spfa找负环 二分就好 code by wzxbeliever: #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 51000 using namespace std; bool vis[N]; int n,m,x,y,z,tot; int c[N],num[N],head[N]; double ans,mid,l,r,w[N],dis[N]; struct Edge { int to,dis,from,next; }edge[N]; int add(int x,int y,int z) { tot++; edge[tot].to=y; edge[tot].dis=z; edge[tot].next=head[x]; head[x]=tot; } int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10