1. 程式人生 > >最優矩陣鏈乘——NBUT 1003

最優矩陣鏈乘——NBUT 1003

思路:也是和紫書上的一樣,如果最後一次乘法是第k個,則從A1,A2,....Ak和Ak+1,Ak+2......An兩個子序列都是最優乘法了,所以我們只需保證兩個子結構最優,而子結構也是可以這樣劃分的,所以我們每次考慮的問題就是,把Ai,Ai+1...Aj乘起來的最少乘法次數,用dp[i][j]表示這個問題的值,有

                                                            dp[i][j]=min{dp[i][k]+dp[k+1][j]+pi-1*pk*pj}

關鍵是遞推的次序要搞明白,當時就沒做出來,還是參考大神的程式碼,按照j-i遞增的方向遞推,因為長區間的值依賴於短區間的值。具體實現還是需要斟酌一下的,程式碼如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;

const int maxn=210;
const int INF=0x3f3f3f3f;
ll dp[maxn][maxn];
ll p[maxn];

/*
     遞推方向如何寫還是比較難想的,長區間的值依賴於短區間,
     所以遞推的方向為j-i的遞增方向,i為集合左端,j為集合右端。
*/

int main()
{
    ll n;
    while(scanf("%lld",&n)!=EOF)
    {
        for(int i=0;i<n+1;i++)
        {
            scanf("%lld",&p[i]);
        }
        //長度為1的矩陣集合,都歸0,沒有乘法計算。
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j)
                    dp[i][j]==0;
            }
        }
        for(int x=2;x<=n;x++)//矩陣集合的長度,2,3....n
        {
            for(int i=1;i<=n-x+1;i++)
            {
                //按照j-i遞增的順序遞推,因為j是矩陣集合的右端,而長區間的值依賴於短區間
                int j=x+i-1;
                dp[i][j]=INF;
                for(int k=i;k<j;k++)
                {
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j]);
                }
            }
        }
        printf("%lld\n",dp[1][n]);
    }
    return 0;
}