题意:有n家餐馆,有m个仓库,然后后来有n个数字,代表了每个餐馆的坐标,0,0表示结束。求餐馆到离它最近仓库的距离和最小,注意仓库都是建立在餐馆上的。输出的时候,要把每个仓库离它最近的餐馆输出。数据范围是餐馆的数目是200。仓库的数目是30个。
如果是x,y之间的餐馆的个数奇数,那么中位数无疑是放仓库的最佳位置,如果是偶数,那么中间两个都可以,因为它们的与到其他餐馆的距离和是相等的。先求出data[i][j]为从餐馆i到餐馆j之间的最小值。map[i][j]定义为前j个餐馆放i个仓库的最小值,那么就可以得到状态转移方程为map[i][j]=min(map[i][j],map[i-1][k]+data[k+1][j])
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=250;
int pos[N],data[N][N],map[35][250];
int iabs(int a){return a>0?a:-a;}
void print_ans(int,int,int);
void fun(int ,int,int );
int main()
{
int n,m,t_cnt=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
memset(map,0x7f,sizeof(map));
memset(data,0,sizeof(data));
for(int i=1;i<=n;i++) scanf("%d",&pos[i]);
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=i;k<=j;k++)
{
data[i][j]+=iabs(pos[k]-pos[(i+j)/2]);
}
}
}
for(int i=1;i<=n;i++) map[1][i]=data[1][i];
for(int i=2;i<=m;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=i-1;k<j;k++)
map[i][j]=min(map[i][j],map[i-1][k]+data[k+1][j]);
}
}
printf("Chain %d\n",++t_cnt);
print_ans(m,n,map[m][n]);
printf("Total distance sum = %d\n\n",map[m][n]);
}
}
void print_ans(int x,int y,int sum)
{
if(x==1){fun(x,x,y); return;}
else
{
for(int i=x;i<=y;i++)
{
if(data[i][y]+map[x-1][i-1]==sum)
{
print_ans(x-1,i-1,sum-data[i][y]);
fun(x,i,y);
break;
}
}
}
}
void fun(int m,int x,int y)
{
if(x==y) printf("Depot %d at restaurant %d serves restaurant %d\n",m,x,y);
else printf("Depot %d at restaurant %d serves restaurants %d to %d\n",m,(x+y)/2,x,y);
}