题意:有n家餐馆,有m个仓库,给出每个餐馆的坐标,0,0表示结束,求餐馆到离它最近仓库的距离和最小,注意仓库都是建立在餐馆上的。输出的时候,要把每个仓库离它最近的餐馆输出。
思路:对于区间(i,j)的餐厅,如果选择一个作为仓库的话,肯定是悬在中位数上,d[i][j]表示区间(i,j)选择一个仓库总的距离和,dp[i][j]表示前j个餐厅建立i个仓库的最小距离
那么 dp[i][j]=min(dp[i][j],dp[i-1][k]+d[k+1][j]);
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=210;
const int maxm=40;
const int INF=0x3f3f3f3f;
int dp[maxm][maxn];
int d[maxn][maxn];
int a[maxn];
int N,K;
int Abs(int x)
{
return x>0?x:-x;
}
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);
}
void dfs(int m,int n,int x)
{
if(m<=1)
{
fun(m,m,n);
return;
}
int pos=0;
for(int j=m;j<=n;j++)
{
if(dp[m-1][j-1]+d[j][n]==x)
{
pos=j;
break;
}
}
dfs(m-1,pos-1,x-d[pos][n]);
fun(m,pos,n);
}
int main()
{
int cas=1;
while(scanf("%d%d",&N,&K)!=EOF,N||K)
{
for(int i=1;i<=N;i++)scanf("%d",&a[i]);
memset(d,0,sizeof(d));
for(int i=1;i<=N;i++)
{
for(int j=i+1;j<=N;j++)
{
for(int k=i;k<=j;k++)
d[i][j]+=Abs(a[k]-a[(i+j)/2]);
}
}
memset(dp,INF,sizeof(dp));
for(int i=1;i<=N;i++)dp[1][i]=d[1][i];
for(int i=2;i<=K;i++)
{
for(int j=i;j<=N;j++)
{
for(int k=i-1;k<j;k++)
dp[i][j]=min(dp[i][j],dp[i-1][k]+d[k+1][j]);
}
}
printf("Chain %d\n",cas++);
dfs(K,N,dp[K][N]);
printf("Total distance sum = %d\n",dp[K][N]);
printf("\n");
}
return 0;
}