石子合并 time limit per test 1 second memory limit per test 256 megabytes 有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。 合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
传送门:NYOJ737
有多组测试数据,输入到文件结束。每组测试数据第一行有一个整数n,表示有n堆石子。接下来的一行有n(1≤n≤199)个数,分别表示这n堆石子的数目,用空格隔开
Output 输出总代价的最小值,占单独的一行
1 2 3 4 3 1 2 3 7 13 7 8 16 21 4 18
Sample Output
题解 学习了一波四边形不等式
对于 f[i][j]= min{f[i][k]+f[k+1][j]+w[i][j]}
凸四边形不等式:w[a][c]+w[b][d]<=w[b][c]+w[a][d] a<b<c<d
区间包含关系单调: w[b][c]<=w[a][d] a<b<c<d
定理1: 如果w同时满足四边形不等式和决策单调性 ,则f也满足四边形不等式
定理2: 若f满足四边形不等式,则决策s满足 s[i][j-1]<=s[i][j]<=s[i+1][j]
定理3: w为凸当且仅当w[i][j]+w[i+1][j+1]<=w[i+1][j]+w[i][j+1]
s代表方案取的下标 初始s[i][i]=i
这样能把O(n^3)的dp化为O(n^2)
## AC code:(不包含输入类)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import java.io.*; import java.util.*; public class Main { static int maxn=(int ) (1e9 +7 ); public static void main (String[] args) { FastScanner sc = new FastScanner(); PrintWriter pw = new PrintWriter(System.out); while (sc.hasNext()) { int n=sc.nextInt(); int []shu=new int [n+1 ]; for (int i=1 ;i<=n;i++)shu[i]=sc.nextInt(); int [][]dp=new int [n+1 ][n+1 ]; int [][]s=new int [n+1 ][n+1 ]; for (int i=1 ;i<=n;i++)Arrays.fill(dp[i], maxn); for (int i=1 ;i<=n;i++){ dp[i][i]=0 ; s[i][i]=i; } int []pre=new int [n+1 ]; for (int i=1 ;i<=n;i++){ pre[i]=pre[i-1 ]+shu[i]; } for (int j=1 ;j<=n;j++){ for (int i=j-1 ;i>=1 ;i--){ for (int k=s[i][j-1 ];k<=s[i+1 ][j];k++){ int temp=dp[i][k-1 ]+dp[k][j]+pre[j]-pre[i-1 ]; if (temp<dp[i][j]){ dp[i][j]=temp; s[i][j]=k; } } } } pw.println(dp[1 ][n]); pw.flush(); } } }