zoukankan      html  css  js  c++  java
  • POJ 1651 Multiplication Puzzle (区间DP OR 记忆化搜索)

    (1)分析最优子结构  在这个问题中想得到a b c d e f之间最小值,比如开始拿d位置的,那么问题就转化成了a b c e和c e f这两个子问题的最小值再加上c*d*e就行了,不过如果真的是这么想的话,也就是把d当成最开始拿的话,怎么表示?开始还想用dp[i][j][k]表示区间i~j之间去掉k后的最小值,但是再解决这个子问题的时候有需要加一维,这样表示就很困难了,虽然子问题分离出来了,但是表示很困难。所以我们可以在重新从另外一种思路想,就是把d当做最后拿的,也就是说在拿d之前b c e已经拿完了,这样就变成了a b c d 和d e f 两个子问题+a*d*f了,表示起来也就简单了,直接用二维表示区间里面的就好了。
    (2)确定dp状态的含义  dp[i][j]区间i~j能得到的最小值
    (3)得到递推方程式

                dp[j][j + i] = min(dp[j][j + i] , dp[j][k] + dp[k][j + i] + a[k] * a[j] * a[j + i]);


    这里突然总结出一个技巧来,就是区间dp因为是需要求区间值的,所以复杂度一般就是O(n^3)(纯二维数组),但是一般DP都是O(n^2)(一般都能用一维数或者滚动数组代替二维数组),并且一般ACM题型判断属于DP类型的是很简单的,但是具体那种DP可能在划分子问题时候还是不太好想的,现在我们就可以用题目中给的数据范围来推测是那种DP了,最起码心里有个数了,算是一种辅助的方式吧!



    #include<stdio.h>
    #include<stdlib.h>
    #include<iostream>
    #include<string.h>
    #define INF 0x3f3f3f3f
    using namespace std;
    int dp[105][105];
    
    int main()
    
    {
    
       int n,i,num[105],len,j;
       while(~scanf("%d",&n))
       {
          memset(num,0,sizeof(num));
          for(i=1;i<=n;i++)
             scanf("%d",&num[i]);
          for(i=1;i<n-1;i++)
             dp[i][i+2]=num[i]*num[i+1]*num[i+2];
          for(len=4;len<=n;len++)   ///先更新小区间,最后得到大区间
          {
             for(i=1;i<=n-len+1;i++)  ///开始位置
             {
                 dp[i][i+len-1]=INF;
                 for(j=i+1;j<i+len-1;j++)  ///最后拿第j个
                 dp[i][i+len-1]=min(dp[i][i+len-1],dp[i][j]+dp[j][i+len-1]+num[i]*num[j]*num[i+len-1]);   
             }
          }
          printf("%d
    ",dp[1][n]);
       }
       return 0;
    }


    Top-Down方式:

    #include<stdio.h>
    #include<string.h>
    #include <iostream>       //用 INT_MAX 要此头文件
     
    int point[100], dp[100][100];
     
    int DP(int left, int right)
    {
        int i, min, l, r, temp;
        if(-1 != dp[left][right])   return dp[left][right];
        if(right-left == 1)         return dp[left][right] = 0;
        min = INT_MAX;
        for(i=left+1; i<right; i++)
        {
            l = DP(left, i);
            r = DP(i, right);
            temp = l + r + point[left] * point[i] * point[right];
            if(min > temp)           min = temp;
        }
        return dp[left][right] = min;
    }
     
    int main()
    {
        int nCard, i;
        while(scanf("%d", &nCard) != EOF)
        {
            memset(dp,-1,sizeof(dp));       //赋值-1
            for(i=0; i<nCard; i++)
                scanf("%d", &point[i]);     //忘记 & ;
            printf("%d
    ", DP(0, nCard-1)); //右参数不是nCard
        }
        return 0;
    }




  • 相关阅读:
    权限管理系统准备
    java启动线程时 extends与implements的一个差异
    spring中使用quartz时注入时出现的错误
    bat执行java程序 good
    bat下执行java程序报错处理
    SQLite.dll在xp中部署时的报错处理
    hdu 4277 USACO ORZ (dfs暴搜+hash)
    Java实现 蓝桥杯 算法训练 动态数组使用
    Java实现 蓝桥杯 算法训练 动态数组使用
    Java实现 蓝桥杯 算法训练 动态数组使用
  • 原文地址:https://www.cnblogs.com/zswbky/p/6792898.html
Copyright © 2011-2022 走看看