1. 程式人生 > >2016級算法第四次上機-A.Bamboo 和人工zz

2016級算法第四次上機-A.Bamboo 和人工zz

amp 循環 倒序 遞歸 int tro n) std 矩陣

Bamboo和人工ZZ

題意:

非常直白,經典的動態規劃矩陣鏈乘問題

分析:

矩陣鏈A1A2..An滿足結合律,可以使用加括號的方式,降低運算代價。
一個pq的矩陣和一個qr的矩陣相乘,計算代價為pqr

加括號時滿足動態規劃的特性
長度為1的矩陣不需要加括號
長度>=2的矩陣鏈AiAi+1.....Aj,勢必在 Ak和Ak+1之間加括號,分成的兩組中各自的加括號方案已經是最優的了。
以m[i][j]表示Ai-Aj矩陣鏈乘的代價,則
核心語句:
i=j m[i][j]=0;
i<j m[i][j] = min(m[i][k] + m[k+1][j] + pi-1pkpj); i<=k<j

l:矩陣鏈長度,長度為1無需考慮
i:與j遍歷所有長度為l的矩陣鏈
k:遍歷所有可能的分割點
保留最小的方案

輸出括號化方案,s[i][j]記錄分割點k,遞歸輸出方案。註意左邊優先,有兩種方式,可以在判斷if(q<=m[i][j])時加上等號;或者內層的k循環倒序

偽代碼

int p[]
int m[][]
int s[][]
void Multiply()
{
    Initialization of m[][]
    for l = 2:n
        for i = 1: n-l+1
        j = i+l-1
        m[i][j]= INF
        for
k = i:=j-1 q = m[i][k]+m[k+1][j]+ p[i-1]*p[k]*p[j] if(q<=m[i][j]) m[i][j] = q s[i][j] = k end end end } void Print( i, j) { if(i==j) printf("A%d",i) else printf("("
) Print(i,s[i][j]) Print(s[i][j]+1, j) printf(")") end }

代碼如下:

#include<stdio.h>
#include<math.h>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int p[310];
int m[305][305];
int s[305][305];
const int INF = 1<<30;
void Mulity(int n)
{
    for(int i = 0;i<=n;i++)
        m[i][i] = 0;
    for(int l = 2; l<=n;l++)
        for(int i = 1; i<= n-l+1;i++)
    {
        int j = i+l-1;
        m[i][j]= INF;
        for(int k = i;k<=j-1;k++)
        {
            int q = m[i][k]+m[k+1][j]+ p[i-1]*p[k]*p[j];
            if(q<=m[i][j])
            {m[i][j] = q;
            s[i][j] = k;
            }
        }
    }
}
void Print(int i,int j)
{
    if(i==j)
        printf("A%d",i);
    else
    {
        printf("(");
        Print(i,s[i][j]);
        Print(s[i][j]+1, j);
        printf(")");
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i = 0;i<=n;i++)
            scanf("%d",&p[i]);
        Mulity(n);
        printf("%d\n",m[1][n]);
        Print(1,n);
        printf("\n");
    }
    }

2016級算法第四次上機-A.Bamboo 和人工zz