题目
思路分析
一开始看数据太大就知道肯定要用动态规划,但失败了(日常蒟蒻 1/∞)。百度题解后才发现自己的状态转移方程有误。状态不应该由前一个餐馆转移过来,应该从上一次建立的存储点转移过来。因此设计状态f[i][j]表示前j个餐馆设立了i个存储点时的最优解。则状态转移方程为
f
[
i
]
[
j
]
=
m
i
n
{
f
[
i
]
[
j
]
,
f
[
i
−
1
]
[
k
]
+
g
[
k
]
[
j
]
}
f[i][j]= min\lbrace f[i][j],f[i-1][k]+g[k][j]\rbrace
f[i][j]=min{f[i][j],f[i−1][k]+g[k][j]}
g[i][j]表示从第I个餐馆到第j个餐馆中建立1个储存点的最优解。这个可以直接预处理出来(利用绝对值函数的性质)
代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAX 0x3f3f3f3f
using namespace std;
int n,k;
int d[205];
int g[205][205],f[35][205];
int main()
{
int cnt=1;
while(scanf("%d%d",&n,&k)!=EOF)
{
if(n==0&&k==0) break;
for(int i=1;i<=n;i++)
scanf("%d",&d[i]);
memset(g,0,sizeof(g));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
int mid=(i+j)/2;
for(int u=i;u<=j;u++)
{
g[i][j]+=abs(d[u]-d[mid]);
}
}
}
for(int i=1;i<=n;i++) f[1][i]=g[1][i];
for(int u=2;u<=k;u++)
{
for(int j=u;j<=n;j++)
{
f[u][j]=MAX;
for(int i=1;i<j;i++)
f[u][j]=min(f[u][j],f[u-1][i]+g[i+1][j]);
}
}
printf("Chain %d\n",cnt);
cnt++;
printf("Total distance sum = %d\n\n",f[k][n]);
}
return 0;
}