區間dp


讓我求解在一個區間上的最優解,那么我把這個區間分割成一個個小區間,求解每個小區間的最優解,再合並小區間得到大區間即可。所以在代碼實現上,我可以枚舉區間長度len為每次分割成的小區間長度(由短到長不斷合並),內層枚舉該長度下可以的起點,自然終點也就明了了。然后在這個起點終點之間枚舉分割點,求解這段小區間在某個分割點下的最優解。

板子:

for(int len = 1;len<=n;len++){//枚舉長度
for(int j = 1;j+len<=n+1;j++){//枚舉起點,ends<=n
int ends = j+len - 1;
for(int i = j;i<ends;i++){//枚舉分割點,更新小區間最優解
dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+something);
}
}
}

注意要點

1.必須先枚舉區間長度l否則會炸。 
2.注意枚舉順序為長度=>起始點=>中間點,起始點循環開始后馬上算終止節點,邊界的節點應該在枚舉中間節點的循環之外進行!
三.朴素區間dp(n^3/2)

51nod 1021石子合並

#include<iostream>
#include<cstring>//MEMSET()函數頭文件
#include<cstdio>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f
int stone[102];
int dp[102][102];
int sum[102];
int main()
{
int n;cin>>n;
memset(sum,0,sizeof(sum));
memset(dp,inf,sizeof(dp));
for(int i=1;i<=n;i++)
{
cin>>stone[i];
sum[i]=sum[i-1]+stone[i];
dp[i][i]=0;
}
for(int len=1;len<=n;len++)//枚舉區間長度
for(int j=1;j+len<=n+1;j++) //枚舉起點
{
int ends=j+len-1;
for(int i=j;i<=ends;i++)//枚舉分割點
{
dp[j][ends]=min(dp[j][ends],dp[j][i]+dp[i+1][ends]+sum[ends]-sum[j-1]);
}
}
cout<<dp[1][n]<<endl;
return 0;
}


免責聲明!

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



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