现在的位置: 首页 > 综合 > 正文

UVA 662 Fast Food

2019年04月06日 ⁄ 综合 ⁄ 共 1340字 ⁄ 字号 评论关闭

大意略。

有些地方参考了别人的博客。

思路:区间DP,一开始根本就没有思路,想了很久,很多方面木有想清楚啊,后来发现DP方程可以这样表示:

dis[i][j]可以表示在餐馆i~j建立仓库的最小距离,最小距离便是在(i+j)/2建立餐馆,这个可以证明的。

d[i][j] = min(d[i][j], d[i-1][k] + dis[k+1][j]);

d[i][j]表示从前j个餐馆内建立i个仓库,d[i-1][k] + dis[k+1][j]表示的是在1~k内范围建有i-1个仓库,而k+1~j的餐馆是由第i个仓库来管理的,于是也变成了在那个最优位置选餐馆的问题了,k的范围(1<=k < j)。

由于题目有序,可以用递归的方式输出路径。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;

const int MAXN = 210;
const int INF = 0x3f3f3f3f;

int N, K;

int dis[MAXN][MAXN];
int d[MAXN][MAXN];
int A[MAXN];
int fa[MAXN][MAXN];

void init()
{
	memset(dis, 0, sizeof(dis));
	memset(d, INF, sizeof(d));
	memset(fa, 0, sizeof(fa));
}

int read_case()
{
	init();
	scanf("%d%d", &N, &K);
	if(!N && !K) return 0;
	for(int i = 1; i <= N; i++) scanf("%d", &A[i]);
	for(int i = 1; i <= N; i++)
	{
		for(int j = 1; j <= N; j++)
		{
			for(int k = i; k <= j; k++)
			{
				dis[i][j] += abs(A[k] - A[(i+j)/2]);
			}
		}
	}
	return 1;
}

int dp()
{
	for(int i = 1; i <= N; i++) d[1][i] = dis[1][i];
	for(int i = 2; i <= K; i++)
	{
		for(int j = 1; j <= N; j++)
		{
			for(int k = 1; k < j; k++)
			{
				if(d[i][j] > d[i-1][k] + dis[k+1][j])
				{
					d[i][j] = d[i-1][k] + dis[k+1][j];
					fa[i][j] = k;
				}
			}
		}
	}
	return d[K][N];
}

void print_ans(int i, int j)
{
	int t = fa[i][j];
	if(t != 1) print_ans(i, t);
	printf("Depot %d at restaurant %d serves restaurants %d to %d\n", i, (t+1+j)/2, t+1, j);
}

void solve()
{
	int ans = dp();
	print_ans(K, N);
	printf("Total distance sum = %d\n", ans);
}

int main()
{
	int times = 0;
	while(read_case())
	{
		printf("Chain %d\n", ++times);
		solve();
		printf("\n");
	}
	return 0;
}

抱歉!评论已关闭.