题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1196
设想状态p(n,k)表示n个店前建k个仓库的最优距离
p(n,k)=min(p(i,k-1)+mindis(i+1,n))
//其中k-1 <= j <= i-1, dis[i][j]表示从第i个饭店到第j个饭店添加一个供应点所达到的最小值,取i,j中间值即可
即我们求出0到i间建设k-1个供应站, 加上i, n之间建一个供应站的最小值. 0到i 有变成了父问题
for 一下i, 然后得一个最小值
dis[i][j]在i, j之间建造一个供应站, 是建在i, j中间的饭店中,即第(i + j) / 2个饭店, 然后i, j 之间每个饭店都要到这个供应站, 求和
置肯定是建在i+1到终点中间,而且m个店前最多也只能建m个仓库,所以i的范围可以确定.......;
#include "iostream"
#include "cstdlib"
using namespace std;
int data[220]; //存储每个餐厅的位置
int mindis[220][220]; //存储 i, j 之间建一个供应站, i, j 之间的餐厅到他的距离和
int result[220][40]; //存储中间结果
int n, k;
int searchResult(int n, int k){
if(n <= k) //n < k 的时候可以写返回999999, 但是我们返回0 也不会对结果影响, 你想少放几个站点会比多放几个少吗
return 0;
if(k == 1)
return mindis[1][n];
if(result[n][k] != -1) //如果我们已经求过n个餐厅建k个供应站, 那么直接返回结果
return result[n][k];
int min = 999999999;
int i;
for(i = k - 1; i < n; i++){
int temp = searchResult(i, k - 1) + mindis[i + 1][n];
if(temp < min)
min = temp;
}
result[n][k] = min;
return min;
}
int main(){
int iCase=0;
while(cin >> n >> k && n && k){
int i, j;
for(i = 1; i <= n; i++){
cin >> data[i];
for(j = 0; j <= n; j++)
result[i][j] = -1; //赋初值
}
int mid;
for(i = 1; i <= n; i++){
mindis[i][i] = 0;
for(j = i + 1; j <= n; j++){
int p;
mindis[i][j] = 0;
mid = (i + j) / 2;
for(p = i; p <= j; p++)
mindis[i][j] += abs(data[p] - data[mid]);
}
}
cout<<"Chain " << ++iCase << endl;
cout<<"Total distance sum = "<< searchResult(n , k ) << endl << endl;
}
return 0;
}