1. 程式人生 > >動態規劃練習——UVa10003——區間dp

動態規劃練習——UVa10003——區間dp

題目連結:https://vjudge.net/contest/232313#problem/I

紫書上的動態規劃例題,很明顯是一個區間線性規劃的問題,想起之前做過的矩陣鏈乘,這題和它很像,列舉方向都是向j-i遞增的

方向,這裡有個大神的區間dp模板的總結:http://www.cnblogs.com/zsboy/archive/2013/03/08/2950261.html可以強化理解。

所以,設dp[i][j]為切割小木棍i~j點的費用,則dp[i][j]=min{dp[i][k]+dp[k][j]+a[j]-a[i]},a[j]-a[i]表示第一刀切割為i~j的費用,而

dp[i][k]和dp[k][j]就像最優矩陣鏈乘一樣,將問題分割為了兩個子問題,所以長區間必須由短區間推得,和紫書上的思路一樣。

程式碼:

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

const int maxn=55;
int a[maxn];
int dp[maxn][maxn];
const int INF=0x3f3f3f3f;

int main()
{
    int l;
    while(scanf("%d",&l)!=EOF)
    {
        if(l==0)break;
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        a[0]=0;
        a[n+1]=l;
        for(int i=0;i<=n+1;i++)
            dp[i][i+1]=0;
        for(int x=1;x<=n+1;x++)//區間長度
        {
            for(int i=0;i<=n+1;i++)//起點
            {
                int j=i+x;//終點
                if(j>n+1)break;
                int minn=INF;
                for(int k=i+1;k<j;k++)
                {
                    int temp=dp[i][k]+dp[k][j]+a[j]-a[i];
                    minn=min(minn,temp);
                }
                if(minn!=INF)
                    dp[i][j]=minn;
            }
        }
        printf("The minimum cutting is %d.\n",dp[0][n+1]);
    }
    return 0;
}