1021 石子归并(区间dp入门)
题目链接:http://www.51nod.com/Challenge/Problem.html#!#problemId=1021
//入门
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int Max_n=105;
int cost[Max_n][Max_n];//记录最小花费
int sum[Max_n],a[Max_n];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(int d=1;d<n;d++){//枚举区间长度-1
for(int i=1,j;(j=i+d)<=n;i++){//枚举起点和终点
cost[i][j]=INT_MAX;
for(int k=i;k<j;k++)//枚举决策点
cost[i][j]=min(cost[i][j],cost[i][k]+cost[k+1][j]);
cost[i][j]+=sum[j]-sum[i-1];
}
}
printf("%d\n",cost[1][n]);
return 0;
}
//四边形优化
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int Max_n=105;
int cost[Max_n][Max_n];//记录最小花费
int sum[Max_n],a[Max_n];
int w[Max_n][Max_n];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(int i=1;i<=n;i++){//只有两堆的情况决策点就是i
cost[i][i+1]=a[i]+a[i+1];
w[i][i+1]=i;
}
for(int d=2;d<n;d++){//枚举区间长度-1(两堆的情况已经计算过,这个三堆起)
for(int i=1,j;(j=i+d)<=n;i++){
//枚举决策点(满足这个不等式就说明决策具有单调性,也就是四边形不等式优化)
cost[i][j]=INT_MAX;
for(int k=w[i][j-1];k<=w[i+1][j];k++){//枚举决策点
if(cost[i][j]>cost[i][k]+cost[k+1][j]){
//此时说明最小值需要改变,决策点需要更新
cost[i][j]=cost[i][k]+cost[k+1][j];
w[i][j]=k;//更新决策点
}
}
cost[i][j]+=sum[j]-sum[i-1];
}
}
printf("%d\n",cost[1][n]);
return 0;
}
1022 石子归并 V2(区间dp四边形优化)
题目链接:http://www.51nod.com/Challenge/Problem.html#!#problemId=1022
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int Max_n=2005;
int cost[Max_n][Max_n];//记录最小花费
int sum[Max_n],a[Max_n];
int w[Max_n][Max_n];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=n+1;i<=2*n;i++)//把前面的接到数组后面,保证我们算到每一个区间
a[i]=a[i-n];
for(int i=1;i<=2*n;i++)
sum[i]=sum[i-1]+a[i];
for(int i=1;i<=2*n;i++){//只有两堆的情况决策点就是i
cost[i][i+1]=a[i]+a[i+1];
w[i][i+1]=i;
}
for(int d=2;d<n;d++){//枚举区间长度-1(两堆的情况已经计算过,这个三堆起)
for(int i=1,j;(j=i+d)<=2*n;i++){
//枚举决策点(满足这个不等式就说明决策具有单调性,也就是四边形不等式优化)
cost[i][j]=INT_MAX;
for(int k=w[i][j-1];k<=w[i+1][j];k++){//枚举决策点
if(cost[i][j]>cost[i][k]+cost[k+1][j]){
//此时说明最小值需要改变,决策点需要更新
cost[i][j]=cost[i][k]+cost[k+1][j];
w[i][j]=k;//更新决策点
}
}
cost[i][j]+=sum[j]-sum[i-1];
}
}
int res=cost[1][n];
for(int i=2;i<=n;i++){
if(res>cost[i][i+n-1])//保持长度是n,相等于决策点在改变
res=cost[i][i+n-1];
}
printf("%d\n",res);
return 0;
}