传送门
设 d ( i , j ) d(i,j) d(i,j)为切割小木棍i~j的最优费用,则 ,其 中最后一项 a [ j ] - a [ i ] a[j]-a[i] a[j]-a[i]代表第一刀的费用。切完之后,小木棍变成 i ~ k i~k i~k和 k ~ j k~j k~j两部分,状态转 移方程由此可得。把切割点编号为 1 ~ n 1~n 1~n,左边界编号为0,右边界编号为 n + 1 n+1 n+1,则答案 为 d ( 0 , n + 1 ) d(0,n+1) d(0,n+1)。
状态有 O ( n 2 ) O(n2) O(n2)个,每个状态的决策有 O ( n ) O(n) O(n)个,时间复杂度为 O ( n 3 ) O(n3) O(n3)。
记忆化搜索:
#include
using namespace std;
const int N=50+5;
int n,L,a[N],vis[N][N],d[N][N];
int dp(int i,int j){
if(i>=j-1) return 0;
if(vis[i][j]) return d[i][j];
vis[i][j]=1;
int& ans=d[i][j];
ans=-1;
for(int k=i+1;k<j;k++){
int v=dp(i,k)+dp(k,j)+a[j]-a[i];
if(ans<0||v<ans) ans=v;
}
return ans;
}
int main(){
while(cin>>L>>n,L){
for(int i=1;i<=n;i++) cin>>a[i];
a[0]=0;a[n+1]=L;
memset(vis,0,sizeof(vis));
printf("The minimum cutting is %d.\n", dp(0, n+1));
}
}
递推:
#include
using namespace std;
const int N=50+5;
int n,L,a[N],d[N][N];
int main(){
while(cin>>L>>n,L){
for(int i=1;i<=n;i++) cin>>a[i];
a[0]=0;a[n+1]=L;
memset(d,0,sizeof(d));
for(int i=0;i<=n+1;i++) d[i][i]=0;
for(int len=1;len<=n+1;len++){
for(int i=0;i+len<=n+1;i++){
int j=i+len;
if(j<=n+1){
for(int k=i+1;k<j;k++){
int v=d[i][k]+d[k][j]+a[j]-a[i];
if(d[i][j]==0||v<d[i][j]) d[i][j]=v;
}
}
}
}
printf("The minimum cutting is %d.\n", d[0][n+1]);
}
}