POJ2671||Jimmy‘s Bad DAY(动态规划)

Jimmy’s Bad Day


Jimmy works in an express company. His job is to deliver the packages to customers as soon as possible. He should deliver all the packages to their customers according to the orders before the end of the day, i.e. 24:00. Any delay should be fined heavily measured by the time he is late for.

It was a bad day. Jimmy’ car was broken. And when he repaired it. It was exactly 24:00. The only thing Jimmy thought then was to find a proper way to deliver to minimize the fine.

He took a look at the map and found that his current position and all the places he would go are on a circle road. And he can drive his car to any place along the circle road clockwise or counter-clockwise. He wanted you to help him to find the best way to minimize the fine.

The fine is described as follows: if Jimmy is late, he has to pay one dollar per minute for each undelivered package.

Input

The input contains several test cases. The first line in each case contains an integer N, no more than 300, where (N-1) is the number of places he has to deliver to. The following N lines describe N points including his current location and the (N-1) destinations he has to go to. These N points are described clockwise based on their locations from Jimmy’s current location. Each line consists of two integers m and t. m is the number of packages ordered by this place, which is always 0 in the first line and positive integers in the other lines. t, measured in minute, represents the time to go from this point to the next (the next point of the (N-1)-th destinations is Jimmy’s current location).

A test case with N = 0 indicates the end of input, and this case should not be processed.

Output

For each test case, you should output one line containing only an integer which is the minimum fine Jimmy has to pay. You can assume that the answer is less than 1000000000 for all test cases.

Sample Input

4
0 1
6 10
9 50
5 5
5
0 2
5 5
4 20
1 20
7 1
0

Sample Output

240
92

Source

Beijing 2005 Preliminary
POJ 2671

题解

题目大意如下:现在是晚上24点,从现在开始每迟一分钟我将向顾客支付罚金一美元,Jimmy的初始位置和N-1个运送点构成一个环,他可以在此环上以任意方向送货,现在要求一个送货方案使罚金最少,输出最少罚金。一共有不多于300个包裹,罚金不会超过10亿美元。

这道题用动态规划求解。假设 dp[0][N-1]是从初始位置开始到运送点N-1之间所需的最少运费。(可结合示意图理解,有点丑qwq将就看)


考 察 其 中 一 段 [ i : j ] : 可 以 从 i 出 发 到 j , 也 可 以 从 j 出 发 到 i 。 考察其中一段[i:j]:可以从i出发到j,也可以从j出发到i。 [i:j]:ijji 两 种 不 同 起 点 所 需 最 少 运 费 分 别 记 作 l [ i ] [ j ] , r [ i ] [ j ] 。 两种不同起点所需最少运费分别记作l[i][j],r[i][j]。 l[i][j],r[i][j]
考 察 其 中 一 种 , 以 l [ i ] [ j ] 为 例 ( r [ i ] [ j ] 是 类 似 的 , 只 是 起 点 和 终 点 调 换 了 ) : 考察其中一种,以l[i][j]为例(r[i][j]是类似的,只是起点和终点调换了): l[i][j]r[i][j]
记 w [ i ] [ j ] 为 [ i : j ] 货 物 总 量 ( 不 包 括 i 点 的 货 物 , 因 为 求 总 的 [ 0 : N − 1 ] 时 , 初 始 位 置 是 没 有 货 物 的 ) ; 记w[i][j]为[i:j]货物总量(不包括i点的货物,因为求总的[0:N-1]时,初始位置是没有货物的); w[i][j][i:j]i[0:N1]
t i m e [ i ] 为 i 到 i + 1 所 需 时 间 。 time[i]为i到i+1所需时间。 time[i]ii+1
有两种求费用的方法:
第一种:
在这里插入图片描述
先从 i 走到 i+1 ,需时间 time[i] ,再从 i+1j
这样所需的费用为,从 i+1j 所需最少费用,因为这是建立在从i出发的基础上,所以还要加上 ii+1 所耗时间产生的罚金。因此费用为
l [ i + 1 ] [ j ] + t i m e [ i ] ∗ w [ i ] [ j ] l[i+1][j]+time[i]*w[i][j] l[i+1][j]+time[i]w[i][j].

第二种:
在这里插入图片描述
记顺时针方向,从 i->0 所需时间为 c[i] ,逆时针方向,从 j->0 所需时间为 ac[j]
先从另一方向由 i 走到 j ,再从 j 走到 i+1 .
可以看出来,这种走法与第一种走法的不同是,把 ii+1 逆时针走替换为了i到j顺时针走。
因此可得费用为:由 ji+1 的最少费用,再加上从 i 顺时针到 j 多花时间所产生的罚金。即: r [ i + 1 ] [ j ] + ( c [ i ] + a c [ j ] ) ∗ w [ i ] [ j ] . r[i+1][j]+(c[i]+ac[j])*w[i][j]. r[i+1][j]+(c[i]+ac[j])w[i][j].

l[i][j] 即为以上两种方法得到的较小值:
l [ i ] [ j ] = m i n ( l [ i + 1 ] [ j ] + t i m e [ i ] ∗ w [ i ] [ j ] , r [ i + 1 ] [ j ] + ( c [ i ] + a c [ j ] ) ∗ w [ i ] [ j ] ) l[i][j]=min(l[i+1][j]+time[i]*w[i][j],r[i+1][j]+(c[i]+ac[j])*w[i][j]) l[i][j]=min(l[i+1][j]+time[i]w[i][j],r[i+1][j]+(c[i]+ac[j])w[i][j])

举个栗子🌰:
在这里插入图片描述
请看上图:(依旧是拉胯的图www)
可以得出 l [ 1 ] [ 3 ] = 240 l[1][3]=240 l[1][3]=240

r[i][j] 的情况不具体分析了,简单画两个示意图:
在这里插入图片描述

所以 d p [ i ] [ j ] = m i n ( l [ i ] [ j ] , r [ i ] [ j ] ) dp[i][j]=min(l[i][j],r[i][j]) dp[i][j]=min(l[i][j],r[i][j])
要求 dp[0][N-1] 的话,只要把 i , j 扩展就好了。

代码

接下来就可以写代码啦:
先初始化 l , r 数组,除了不移动的情况,初始值都为无穷大(后面要求 min);
还有用输入的货物件数初始化某段货物总件数,用输入的时间初始化与时间相关的三个数组。
然后自底向上dp,把所得的每一段结果都求出来,最后到整个路径,选择 l , r 两种方式较小的费用即为答案。

#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x7f7f7f7f;
int Time[305];
int num[305];
int c[305];
int ac[305];
int l[305][305], r[305][305], w[305][305];
int main() {
	int N;
	while (true) {
		scanf_s("%d", &N);
		if (!N) break;
		for (int i = 0; i < N; i++) {
			scanf_s("%d %d", &num[i], &Time[i]);
		}
		//初始化
		c[0] = 0;
		num[N] = 0;
		Time[N] = 0;
		N++;
		ac[N] = 0;
		for (int i = 1; i < N; i++) {
			c[i] = c[i - 1] + Time[i - 1];
		}
		for (int i = N - 1; i >= 0; i--) {
			ac[i] = ac[i + 1] + Time[i];
		}
		for (int i = 0; i < N; i++) {
			w[i][i] = num[i];
			for (int j = i + 1; j < N; j++)
				w[i][j] = w[i][j - 1] + num[j];
		}
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (i == j) {
					l[i][j] = r[i][j] = 0;
				}
				else {
					l[i][j] = r[i][j] = INF;
				}
			}
		}
		int j;
		//自底向上,求0到N-1所需最小费用
		for (int span = 1; span < N; span++) {
			for (int i = 0; i + span < N; i++) {
				j = i + span;
				l[i][j] = min(l[i + 1][j] + Time[i] * w[i + 1][j], r[i + 1][j] + (c[i] + ac[j]) * w[i + 1][j]);
				r[i][j] = min(r[i][j - 1] + Time[j - 1] * w[i][j - 1], l[i][j - 1] + (c[i] + ac[j]) * w[i][j - 1]);
			}
		}
		cout << min(l[0][N - 1], r[0][N - 1]) << endl;
	}
}

这个思路参考了以下几位大佬的题解:

https://blog.csdn.net/zhj12399/article/details/113618726
https://www.cnblogs.com/AbandonZHANG/archive/2013/03/12/4114226.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值