HUD 1227 && POJ 1485 && ZOJ 1196

嗯,题意比较容易理解,在高速公路旁有一些快餐店,然后每一个快餐店距高速出口的距离给出,在这几个快餐店中的K个建仓库,使每个快餐店到其最近的仓库距离和最短。

并输出方案(可能有多个,求解任意一个)

典型的DP 前i个神马东西里面选几个东西的问题吧属于,但是路径不会!参考别人代码,不要喷我!

/*
转移方程:dp[i][j] = min(dp[k][j-1] + cost[k+1][i]);
表示前i个餐馆建设j个仓库 = 前k个餐馆建设j-1个仓库 + k+1个参观到第i个餐馆建设一个仓库的最小值
cost[i][j] 表示从i到j建设仓库路程最小值 ,显而易见 在(i+j)/2处建设可得距离差最短(不明白可以简单模拟下)
路径存储:没有想出来好的办法,借鉴别人思路,递归求解。
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define INF 0x6ffffff
#define NN 210
int d[NN],dp[NN][NN/6],cost[NN][NN];
int from[NN][NN/6],to[NN][NN/6],at[NN][NN/6];
int n,K;
int PrintPath(int i,int j)
{
	int num;
	if(j<=0 ||i<=0)return 1;
	num = PrintPath(from[i][j]-1,j-1);
	printf("Depot %d at restaurant %d serves ",num,at[i][j]);
	if(from[i][j] == to[i][j])printf("restaurant %d\n",from[i][j]);
	else printf("restaurants %d to %d\n",from[i][j],to[i][j]);
	return num +1;
}
void DP()
{
	int i,j,mid,k,sum,min;
	for(i=1;i<=n;i++){
		for(j=i;j<=n;j++){
			mid = (i+j)/2;
			for(k=i;k<mid;k++)
				cost[i][j]+=d[mid]-d[k];
			for(k=mid+1;k<=j;k++)
				cost[i][j]+=d[k]-d[mid];
		}
	}//计算cost[i][j]
	//DP前初始化
	for(i=1;i<=n;i++)dp[i][0]=INF;
	for(i=1;i<=n;i++){
		for(j=1;j<=K && j<=i;j++){
			min = INF;
			for(k=j-1;k<i;k++){
				sum = dp[k][j-1] + cost [k+1][i];
				if(sum < min){
					min = sum;
					from[i][j] = k+1;
					to[i][j] = i;
					at[i][j] = (k+i+1)/2;
				}
			}
			dp[i][j]=min;
		}
	}
}       

int main()
{
	int i,c=1;
	while(~scanf("%d%d",&n,&K),n||K){
		for(i=1;i<=n;i++)scanf("%d",&d[i]);
		printf("Chain %d\n",c++);
		DP();
		PrintPath(n,K);
		printf("Total distance sum = %d\n\n",dp[n][K]);
		memset(dp,0,sizeof(dp));
		memset(cost,0,sizeof(cost));
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值