UVA_662

    首先我们考虑区间[i,j]内如果建一个餐馆应该建在哪个位置,比较容易证明应该是建在中间的位置,如果是偶数个元素,中间两个位置随便一个都可以。这样我们就可以预处理出区间[i,j]内建一个餐馆的最小总路程A[i][j]了。

    我们可以用f[i][j]表示第i个餐馆服务到第j个位置所需的最小总路程,那么f[i][j]=min{f[i-1][k]+A[k+1][j]},其中i-1<=k<j。

#include<stdio.h>
#include<string.h>
#define MAXD 210
#define MAXK 40
#define INF 0x3f3f3f3f
int N, K, f[MAXK][MAXD], p[MAXK][MAXD], a[MAXD], b[MAXD];
int A[MAXD][MAXD], s[MAXD];
int init()
{
int i, j, k, temp;
scanf("%d%d", &N, &K);
if(!N && !K)
return 0;
s[0] = 0;
for(i = 1; i <= N; i ++)
{
scanf("%d", &a[i]);
s[i] = a[i] + s[i - 1];
}
for(i = 1; i <= N; i ++)
for(j = i; j <= N; j ++)
{
k = (i + j) / 2;
temp = s[j] - s[k] - (j - k) * a[k];
temp += (k - i) * a[k] - s[k - 1] + s[i - 1];
A[i][j] = temp;
}
return 1;
}
void printpath(int k, int n)
{
int t = p[k][n];
if(k != 1)
printpath(k - 1, t);
printf("Depot %d at restaurant %d serves restaurants %d to %d\n", k, (t + 1 + n) / 2, t + 1, n);
}
void solve()
{
int i, j, k, min;
memset(f, 0x3f, sizeof(f));
for(k = 1; k <= N; k ++)
f[1][k] = A[1][k];
for(i = 2; i <= K; i ++)
for(j = i; j <= N; j ++)
for(k = i - 1; k < j; k ++)
{
if(f[i - 1][k] + A[k + 1][j] < f[i][j])
{
f[i][j] = f[i - 1][k] + A[k + 1][j];
p[i][j] = k;
}
}
printpath(K, N);
printf("Total distance sum = %d\n", f[K][N]);
}
int main()
{
int t = 0;
while(init())
{
printf("Chain %d\n", ++ t);
solve();
printf("\n");
}
return 0;
}


posted on 2011-12-04 22:24  Staginner  阅读(422)  评论(0编辑  收藏  举报