區間DP總結


做了一些區間DP的題目,總結如下

 

1.Multiplication Puzzle

原題地址:http://poj.org/problem?id=1651

題意:

給定一個序列,可以依次從序列中取走除了左右兩端點之外的元素,每次取走一個元素,獲得該元素乘以它左右兩邊元素乘積的點數,求可能的最小點數

題解:

枚舉區間中最后一個被取走的元素,實現區間的分割,也就是狀態的轉移。

詳細的解題報告

 

2.Dire Wolf

原題地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=5115

題意:

有一群狼站成一排,每個狼有基礎的攻擊力,同時有一個輔助攻擊力,每個狼的總攻擊力是基礎攻擊力加上相鄰的狼給予的輔助攻擊力之和,求殺狼的次序使得收到的總攻擊力之和最小。

題解:和上一題非常相似

#include<bits/stdc++.h>

#define clr(x,y) memset((x),(y),sizeof(x))

using namespace std;
typedef long long LL;

const int maxn=200;
const int inf=1e9;

int A[maxn+5];
int B[maxn+5];
int dp[maxn+5][maxn+5];
int n;

int DP(int l,int r)
{
    if (dp[l][r]!=-1) return dp[l][r];
    if (l==r-1) return dp[l][r]=0;

    dp[l][r]=inf;
    for (int k=l+1;k<=r-1;++k)
    {
        int tmp=A[k]+B[l]+B[r];
        dp[l][r]=min(dp[l][r],DP(l,k)+DP(k,r)+tmp);
    }
    return dp[l][r];
}
void solve(int C)
{
    A[0]=0;
    A[n+1]=0;
    B[0]=0;
    B[n+1]=0;

    clr(dp,-1);
    int ans=DP(0,n+1);

    printf("Case #%d: %d\n",C,ans);
}

int main(void)
{
    #ifdef ex
    freopen ("../in.txt","r",stdin);
    //freopen ("../out.txt","w",stdout);
    #endif

    int T;
    scanf("%d",&T);

    for (int Case=1;Case<=T;++Case)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;++i) scanf("%d",&A[i]);
        for (int i=1;i<=n;++i) scanf("%d",&B[i]);

        solve(Case);
    }
}
View Code

 

3.男神的禮物

原題地址:http://acm.uestc.edu.cn/#/problem/show/1131

題意:略

題解:略

#include<bits/stdc++.h>

#define clr(x,y) memset((x),(y),sizeof(x))

using namespace std;
typedef long long LL;

const int maxn=100;
const int inf=1e6;

int n;
int dp[maxn+5][maxn+5];
int A[maxn+5];
int sum[maxn+5];

void solve()
{
    clr(dp,0);
    clr(sum,0);
    for (int i=1;i<=n;++i)
        sum[i]=(sum[i-1]+A[i])%100;

    for (int i=n;i>=1;--i)
    {
        for (int j=i;j<=n;++j)
        {
            dp[i][j]=inf;
            if (i==j) dp[i][j]=0;
            for (int k=i;k<=j-1;++k)
            {
                int c1=(sum[k]-sum[i-1]+100)%100;
                int c2=(sum[j]-sum[k]+100)%100;
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+c1*c2);
            }
            //printf("%d %d %d\n",i,j,dp[i][j]);
        }
    }

    printf("%d\n",dp[1][n]);
}

int main(void)
{
    #ifdef ex
    freopen ("../in.txt","r",stdin);
    //freopen ("../out.txt","w",stdout);
    #endif

    int T;
    scanf("%d",&T);

    while (T--)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;++i) scanf("%d",&A[i]);

        solve();
    }
}
View Code

(對於區間DP,循環的寫法相比記憶化要快若干倍,但是也更容易寫錯,包括初始化,邊界條件等都需要注意)

 

4.You Are the One (難)

原題地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=4283

題意:略

題解:通過枚舉區間左端點的出棧時間實現了區間的分割

詳細的解題報告

 

5.Coloring Brackets

原題地址:http://www.codeforces.com/contest/149/problem/D

題意:略

題解:略

詳細的解題報告

 

6.柱爺的戀愛

原題地址:http://acm.uestc.edu.cn/#/problem/show/1321

題意:略

題解:枚舉左端點的配對括號來實現區間的分割。

詳細的解題報告

 

總結:

區間DP主要涉及兩類問題,區間最優解和區間計數。

區間最優解往往要枚舉區間的分界點,分割區間,子區間的最優解合並之后就是原區間的最優解。

區間計數往往也要分割區間,但是有不遺漏不重復的要求,以上的兩道題都用到了枚舉左端點對應元素的技巧。

區間的分割是區間DP的重要思想

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM