zoukankan      html  css  js  c++  java
  • dp[2019.5.25]

      1、实例计算(写出计算过程):

        1)对维数为序列<5, 10, 3, 12, 5, 50, 6>的各矩阵,找出其矩阵链乘积的一个最优加全部括号。

        这是一个矩阵连乘问题,基本知识可以参考:

        就本题分析如下:

    用递推公式

    m[i][j]表示为:

    i=j时,m[i][j]填0;i>j时,m[i][j]为空;i>j时,求min。

    后一级基于前一级dp出的最优解(每一级即与对角线平行的线)

    ij     1      2      3      4      5        6   

    1      0    

    2              0

    3                     0

    4                             0

    5                                     0

    6                                              0

    ----------------------------------------------

    i=1,j=2:m[1][2]=min{0+0+5×10×3}=150;

    i=2,j=3:m[2][3]=min{0+0+10×3×12}=360;

    i=3,j=4:m[3][4]=min{0+0+3×12×5}=180;

    i=4,j=5:m[4][5]=min{0+0+12×5×50}=3000;

    i=5,j=6:m[5][6]=min{0+0+5×50×6}=1500;

    ij     1        2       3        4        5         6   

    1      0     150

    2              0     360

    3                        0      180

    4                                   0   3000

    5                                           0     1500

    6                                                      0

    ------------------------------------------------

    i=1,j=3:

    m[1][3]

    =min{m[1][1]+m[2][3]+p0p1p3,m[1][2]+m[3][3]+p0p2p3} //m[2][3]和m[1][2]就用前一级的360和150

    =min{0+360+5×10×12,150+0+5×3×12}

    =330;

    i=2,j=4:

    m[2][4]

    =min{m[2][2]+m[3][4]+p1p2p4,m[2][3]+m[4][4]+p1p3p4} //m[3][4]和m[2][3]就用前一级的180和360

    =min{0+180+10×3×5,360+0+10×12×5}

    =330;

    i=3,j=5:

    m[3][5]

    =min{m[3][3]+m[4][5]+p2p3p5,m[3][4]+m[5][5]+p2p4p5}//m[4][5]和m[3][4]就用前一级的3000和180

    =min{0+3000+3×12×5,180+0+3×5×50}

    =930;

    i=4,j=6:

    m[4][6]

    =min{m[4][4]+m[5][6]+p3p4p6,m[4][5]+m[6][6]+p3p5p6}//m[5][6]和m[4][5]就用前一级的1500和3000

    =min{0+1500+12×5×6,3000+0+12×50×6}

    =1860;

    ij     1      2         3          4        5         6   

    1      0     150    330 

    2              0       360     330

    3                         0       180   930

    4                                     0    3000   1860

    5                                              0      1500

    6                                                          0

    ----------------------------------------------------------

    i=1,j=4:

    m[1][4]

    =min{m[1][1]+m[2][4]+p0p1p4,m[1][2]+m[3][4]+p0p2p4,m[1][3]+m[4][4]+p0p3p4}

    =min{0+330+5×10×5,150+180+5×3×5,330+0+5×12×5}

    =min{580,405,630}

    =405

    i=2,j=5:

    m[2][5]

    =min{m[2][2]+m[3][5]+p1p2p5,m[2][3]+m[4][5]+p1p3p5,m[2][4]+m[5][5]+p1p4p5}

    =min{0+930+10×3×50,360+3000+10×12×50,330+0+10×5×50}

    =min{2430,9360,2830}

    =2430

    i=3,j=6:

    m[3][6]

    =min{m[3][3]+m[4][6]+p2p3p6,m[3][4]+m[5][6]+p2p4p6,m[3][5]+m[6][6]+p2p5p6}

    =min{0+1860+3×12×6,180+1500+3×5×6,930+0+3×50×6

    =min{2076,1770,1830}

    =1770

    ij     1      2        3         4          5           6   

    1      0     150    330    405

    2              0       360    330     2430

    3                         0      180      930    1770

    4                                  0        3000   1860

    5                                               0      1500

    6                                                          0

    ----------------------------------------------------------

    i=1,j=5:

    m[1][5]

    =min{m[1][1]+m[2][5]+p0p1p5,m[1][2]+m[3][5]+p0p2p5,

    m[1][3]+m[4][5]+p0p3p5,m[1][4]+m[5][5]+p0p4p5}

    =min{0+2430+5×10×50,150+930+5×3×50,330+3000+5×12×50,405+0+5×5×50}

    =min{4930,1830,6330,1655}

    =1655

    i=2,j=6:

    m[2][6]

    =min{m[2][2]+m[3][6]+p1p2p6,m[2][3]+m[4][6]+p1p3p6,

    m[2][4]+m[5][6]+p1p4p6,m[2][5]+m[6][6]+p1p5p6}

    =min{0+1770+10×3×6,360+3000+10×12×6,330+1500+10×5×6,2430+0+10×50×6}

    =min{,4080,2130,5430}

    =1950

    ij     1      2      3        4        5        6   

    1      0    150  330    405   1655

    2              0    360    330    2430   1950

    3                      0      180      930   1770

    4                                0       3000   1860

    5                                             0     1500

    6                                                         0

    ----------------------------------------------------------

    终于到最后了,只要求出m[1][6]就可以了!

    m[1][6]

    =min{m[1][1]+m[2][6]+p0p1p6,m[1][2]+m[3][6]+p0p2p6,

    m[1][3]+m[4][6]+p0p3p6,m[1][4]+m[5][6]+p0p4p6,m[1][5]+m[6][6]+p0p5p6}

    =min{0+1950+5×10×6,150+1770+5×3×6,

    330+1860+5×12×6,405+1500+5×5×6,1655+0+5×50×6}

    =min{2250,2010,2550,2055,3155}

    =2010

    所以矩阵连乘的最小值m[1][6]=2010

    此时,

    m[1][6]=m[1][2]+m[3][6]+p0p2p6

    m[3][6]= m[3][4]+m[5][6]+p2p4p6

    画的括号为:(A1A2)  (  (A3A4) (A5A6)  )

      核心代码:

    void matrixChain(int p[],int m[][],int s[][])
    //p用来记录矩阵,m[i][j]表示第i个矩阵到第j个矩阵的最优解,s[][]记录从哪里断开可以得到最优解
    {
        int n=len-1;
        for(int i=1; i<=n; i++)//初始化数组
            m[i][j]=0;
        for(int r=2; r<=n; r++)//对角线循环
        {
            for(int i=1; i<=n-r+1; i++) //行循环
            {
                int j=i+r-1;//列的控制
                m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];//找m[i][j]的最小值,初始化使k=i;
                s[i][j]=i;
                for(int k=i+1; k<j; k++)
                {
                    int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
                    if(t<m[i][j])
                    {
                        s[i][j]=k;//在k位置断开得到最优解
                        m[i][j]=t;
                    }
                }
            }
        }
    }

        2)确定<1, 0, 0, 1, 0, 1, 0, 1>和<0, 1, 0, 1, 1, 0, 1, 1, 0>的一个最长公共子序列LCS。

        板子题,直接套之前写的那篇:https://www.cnblogs.com/fangxiaoqi/p/10915451.html

    #include<bits/stdc++.h>
    #define MAX 5005
    using namespace std;
    int f[MAX][MAX];
    string s,t;
    int main(){
        while(cin>>s>>t){
            for(int i=1;i<=s.length();i++)
                for(int j=1;j<=t.length();j++){
                    f[i][j]=max(f[i-1][j],f[i][j-1]);
                    if(s[i-1]==t[j-1])
                    f[i][j]=max(f[i][j],f[i-1][j-1]+1);
           }
           cout<<f[s.length()][t.length()]<<endl;
        }
        return 0;
    }

      2、算法设计

        1)问题:有n个物品,第i个物品价值为vi,重量为wi,其中vi和wi均为非负数,背包的容量为W,W为非负数。现需要考虑如何选择装入背包的物品,使装入背包的物品总价值最大。

    用dp解背包

    假定一组数据:

    vi  4  5  10  11  13

    wi  3  4  7   8   9

    ①    分析最优解的结构

      如果背包最优解中有物品n,xn=1,那么x1----x(n-1)就是这n-1个子问题在容量W-wn时的最优解。如果背包最优解中无n,xn=0,那么x1-----x(n-1)一定构成这n-1个子问题在W时的最优解。

    ②    建立递归关系

      设m[i,w]为背包容量w时i个物品导致的最优解的总价值,根据递归关系导出状态转移方程:

      If i>0&&wi<=w

        m[I,w]=max{m[i-1,w-wi]+vi,m[i-1,w]}

      else

        m[I,w]=m[i-1,w]

    ③    计算最优值

      最优值就是m[i,w],对应的放置内容从后向前逐级递归。

        2)一个序列有N个数:A[1],A[2],…,A[N],求出最长上升子序列的长度(LIS:longest increasing subsequence)。例如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 5, 9) , (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 9) ,(1, 3, 5, 8)和(1, 3, 4, 8).

        最大递增子序列,直接套之前写的代码:https://www.cnblogs.com/fangxiaoqi/p/10915452.html

    #include<bits/stdc++.h>
    using namespace std;
    int sum[1001],a[1001];
    int main(){
        int i,n,mmax=0,maxa=0;
        while(cin>>n && n){
            memset(a,0,sizeof(a));
            for(i=1; i<=n; i++){
                cin>>a[i];
            }
            for(i=1; i<=n; i++){
                mmax = 0;
                for(int j=1; j<i; j++)
                    if(a[j] < a[i])
                        mmax = max(sum[j],mmax);
                sum[i] = mmax + a[i];
                maxa = max(maxa,sum[i]);
            }
            cout<<maxa<<endl;
            maxa = 0;
        }
        return 0;
    }

        3)问题描述 :设有一个长度N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。

           例子:有一个数字串: 312,当N=3,K=1时会有以下两种分法:

             1)3*12=36

             2)31*2=62

           这时,符合题目要求的结果是: 31*2=62

          现在,请你设计一个程序,求得正确的答案。

    分析:

    这个问题有dp的最优子结构,以插入的乘号数来划分阶段,若插入K个乘号,问题是一种K个阶段的决策问题,记m[i][k]表示在前i位数中插入K个乘号所得的max,用来保存每个阶段的状态,a{j}[i]表示从j位到第i位组成的数字。

    得到状态转移方程:

    m[i][k] = max{m[j][k-1]*a[j+1][i]}    (k<=j<=i)

    && m[j][0] = a[1][j]    (1<j<=i)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
           int K,N,i,j,k;
           char s[41];
           int dp[41][7];
           int num[41][41];
           cin >> N >> K >> s;
           memset(dp,0,sizeof(dp));
           for(i=0;i<N;i++){
                  int temp = 0;
                  for(j=i;j<N;j++){
                         temp = temp*10 + s[j] - '0';
                         num[i][j] = temp;
                  }
           }
           for(i=0;i<N;i++)
                  dp[i][0] = num[0][i];
           for(i=0;i<N;i++)
                  for(j=1;j<=K;j++)
                         for(k=0;k<i;k++)
                                dp[i][j] = max(dp[k][j-1]*num[k+1][i],dp[i][j]);
           cout << dp[N-1][K] << endl;
           return 0;
    }
  • 相关阅读:
    20100720 14:14 转:BW十日谈之标准数据源
    BW会计年度期间转换出错
    SQL Server 2005 Logon Triggers 详细介绍
    作业输出文档维护
    windows 系统监视器 以及建议阀值
    linkedserver 的使用
    DAC 连接数据库需要做些什么
    SQL Server 2008新特性 Merge 详细见联机手册
    【20110406】提高数据库可用性需要注意的问题
    索引迁移
  • 原文地址:https://www.cnblogs.com/cruelty_angel/p/11021073.html
Copyright © 2011-2022 走看看