「区间DP-步入」凸多边形的划分

凸多边形的划分

题目描述

给定一个具有N个顶点的凸多边形,将顶点从1至N标号,每个顶点的权值都是一个正整数。将这个凸多边形划分成N-2个互不相交的三角形,试求这些三角形顶点的权值乘积和至少为多少。

输入描述

输入第一行为顶点数N第二行依次为顶点1至顶点N的权值。

输出描述

输出仅一行,为这些三角形顶点的权值乘积和的最小值。

样例

5
121 122 123 245 231
12214884

说明

  • 对于100% 的数据,有 N ≤ 50 N \leq 50 N50 ,每个点权值小于 1 0 9 10^9 109
  • https://ac.nowcoder.com/acm/problem/50500

解析

1643528400834

按照以往的套路,题目要求说明,我们就做什么假设,假设 [ i , j ] [i,j] [i,j] 为最小划分三角形。

以 BE ( [ 2 , 5 ] [2,5] [2,5])为例,以 BE 为固定边做辅助线,可作出 BD 或 EC,分别可以划分三角形为 EBD 与 BDC 或 BEC 和 CED,其中划分的点 D 与 C 称为分界点 K。

可得方程:
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k ] [ j ] + A [ i ] ∗ A [ j ] ∗ A [ k ] ) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + A[i] * A[j] * A[k]) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+A[i]A[j]A[k])
初始化:

  • d p [ i ] [ j ] = I N F dp[i][j] = INF dp[i][j]=INF

代码

以下代码只能获得 40 分(方便理解DP过程)

public class Main {
    
    
    static final int INF = 1 << 30;
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] A = new int[n+1];
        long[][] dp = new long[n+1][n+1];
        for(int i = 1; i <= n; i++) A[i] = sc.nextInt();
        for(int len = 3; len <= n; len++) {
    
    
            for(int i = 1; i + len - 1 <= n; i++) {
    
    
                int j = i + len - 1;
                dp[i][j] = INF;
                for(int k = i + 1; k < j; k++) {
    
    
                    dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k][j] + (A[i] * A[j] * A[k]));
                }
            }
        }
        System.out.println(dp[1][n]);
    }
}

AC 代码

public class Main {
    
    
    static BigInteger INF = new BigInteger("1000000000000000000000000000");
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        BigInteger[] A = new BigInteger[n+1];
        BigInteger[][] dp = new BigInteger[n+1][n+1];
        
        for(int i = 1; i <= n; i++) Arrays.fill(dp[i], new BigInteger("0"));
        for(int i = 1; i <= n; i++) A[i] = new BigInteger(sc.nextInt() + "");
        
        for(int len = 3; len <= n; len++) {
    
     // 枚举区间
            for(int i = 1; i + len - 1 <= n; i++) {
    
     // 枚举区间起点
                int j = i + len - 1; // 计算区间终点
                dp[i][j] = INF;
                for(int k = i + 1; k < j; k++) {
    
     // 枚举分界点
                    BigInteger a = dp[i][j];
                    BigInteger t = new BigInteger("0");
                    if(dp[i][k] != null) t = t.add(dp[i][k]);
                    if(dp[k][j] != null) t = t.add(dp[k][j]);
                    if(A[i] != null && A[j] != null && A[k] != null) t = t.add(A[i].multiply(A[j]).multiply(A[k]));
                    if(a.compareTo(t) >= 1) dp[i][j] = t;
                }
            }
        }
        
        System.out.println(dp[1][n]);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43098197/article/details/130318282