#include <bits/stdc++.h>
using namespace std;
const int maxn=120,inf=1000000;
int dp[maxn][maxn][maxn],d[maxn],mi,ma;
int n;
int init()
{
for(int i=1;i<=n;i++)
{
cin>>d[i];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
{
dp[i][j][k]=-1;
}
for(int i=1;i<=n;i++)
{
dp[i][i][1]=d[i];
}
}
int solve(int l,int r,int k)
{
if(dp[l][r][k]==-2)return -2;
if(l==r&&dp[l][r][k]!=-1)return 0;
if(dp[l][r][k]!=-1)return dp[l][r][k];
if(k==1)
{int m=inf;
if(l!=r+1)
{
for(int i=mi;i<=ma;i++)
{
int cur=solve(l,r,i);
if(m>cur&&cur>=0){m=cur;}
}
}
else m=0;
if(m!=inf)
for(int i=l;i<=r;i++)
{
m+=d[i];
}
else m=-2;
dp[l][r][1]=m;
return m;
}
int m=inf;
for(int i=l;i<r;i++)
{
int cur1=solve(l,i,1),cur2=solve(i+1,r,k-1);
if(cur1==-2||cur2==-2)continue;//{dp[l][r][k]=-2;return -2;}
if(m>cur1+cur2){ if(l==i)cur1=0;if(i+1==r)cur2=0; m=cur1+cur2;}
}
if(m>=inf){dp[l][r][k]=-2;return -2;}
else dp[l][r][k]=m;
return m;
}
int main()
{
while( cin>>n>>mi>>ma)
{init();
int cc=solve(1,n,1);
if(cc<0)cc=0;
cout<<cc<<endl;
}
return 0;
}
pangu and stones(區間dp)
題意:有N堆石子,每次能夠合併連續的、大於等於L、小於等於R堆石子,代價是這些石子的個數和。問合併成一堆石子的代價最小值。
使用一個dp[l][r][k]記錄將區間[l,r]的石子合併爲k堆需要的最小代價。用一個d[i]記錄第k堆石子有幾個石子
轉移方程:dp(l,r,k)=min{dp(l,i,1)+dp(i+1,r,k-1)},l<=i<k
dp(l,r,1)=min{dp(l,r,x)}+(d[l]+…+d[r]),L<=x<=R
//當時在現場賽的時候沒推出來轉移方程,胡亂分析了四個小時,甚至隊員想出了dfs離散化之類的騷操作...然並卵還是沒做出來然後打鐵回家
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.