uva 662 Fast Food

题意:有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);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值