NKOJ P1006 护卫队

NKOJ P1006 护卫队

Description

护卫车队在一条单行的街道前排成一队,前面河上是一座单行的桥。因为街道是一条单行道,所以任何车辆都不能超车。桥能承受一个给定的最大承载量。为了控制桥上的交通,桥两边各站一个指挥员。护卫车队被分成几个组,每组中的车辆都能同时通过该桥。当一组车队到达了桥的另一端,该端的指挥员就用电话通知另一端的指挥员,这样下一组车队才能开始通过该桥。每辆车的重量是已知的。任何一组车队的重量之和不能超过桥的最大承重量。被分在同一组的每一辆车都以其最快的速度通过该桥。一组车队通过该桥的时间是用该车队中速度最慢的车通过该桥所需的时间来表示的。问题要求计算出全部护卫车队通过该桥所需的最短时间值。

Input Format

输入文件第一行包含三个正整数(用空格隔开),第一个整数表示该桥所能承受的最大载重量(用吨表示);第二个整数表示该桥的长度(用千米表示);第三个整数表示该护卫队中车辆的总数(n<1000)。接下来的几行中,每行包含两个正整数W和S(用空格隔开),W表示该车的重量(用吨表示),S表示该车过桥能达到的最快速度(用千米/小时表示)。车子的重量和速度是按车子排队等候时的顺序给出的。

Output Format

输出文件应该是一个实数,四舍五入精确到小数点后1位,表示整个护卫车队通过该桥所需的最短时间(用分钟表示)。

Sample Input 1
100 5 10
40 25
50 20
50 20
70 10
12 50
9 70
49 30
38 25
27 50
19 70

Sample Output 1
75.0

Sample Input 2
5 5 5
1 10
3 10
1 1
4 1
1 10

Sample Output 2
360.0

题目分析:

本题最大的难点:这其实是一道阅读题

题目人话翻译:有n个护卫队,给出每个护卫队重量与其行车速度,再给出桥的载重量与长度,求所有护卫队全部过桥的最短耗时。

显然在输入时,我们可以“顺便”计算出护卫队过桥的耗时,将其存到 S S 数组中。

这道题是求出最短耗时,并且 n n 为1000,显然时间复杂度为 O ( N 2 ) O(N^2) ,于是二话不说就开始DP。

状态:

对于这道题而言,状态没什么好说的,用 f i f_i 表示前i个护卫队全部过桥的最短耗时。

决策:

从我们规定的状态推导,对于每个 f i f_i ,有如下几个决策:

第一种,护卫队 i i 单独过桥。

第二种,护卫队和其他的护卫队 i 1 , i 2 , i 3 i-1,i-2,i-3…… 一起过桥(显然是在不超重的前提下)。

状态转移方程:

只要定好了决策,方程也就是唾手可得的事情了。

f i = m i n { f i 1 + s i f i 2 + s i + s i 1 f i 3 + s i + s i 1 + s i 2 f i j + i j + 1 i S j 1 i + j 1 i W f_i = min\begin{cases}f_{i-1} + s_i\\f_{i-2} + s_i + s_{i-1}\\f_{i-3}+s_i+s_{i-1}+s_{i-2}\\……\\f_{i-j}+\sum^{i}_{i-j+1}S(j\geq 1 且\sum^{i}_{i+j-1}W\leq桥最大能承受的重量)\end{cases}

阶段:

从方程可知, i i 应当是从前往后枚举的。

注意!

这道题在NKOJ上可以轻松水过,但在你谷上由于数据太大,要开longlong和double,初始化时INF也必须设为比 i n t int 的极限还大得值,并且在输出时再转换成分钟的单位(不要问我怎么知道这些的)

C o d e : Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cassert>
#define int long long//防你谷毒瘤

using namespace std;

int w[1005];
double s[1005], f[1005];
//w数组记录护卫队重量,s记录通过大桥需要的时间

signed main()
{
	int t, l, n;
	scanf("%lld%lld%lld", &t, &l, &n);
	for (int i = 1; i <= n; i ++)
	scanf("%lld%lf", w + i, s + i), s[i] = (double) l / s[i];
	for (int i = 1; i <= n; i ++)
	f[i] = 0x7ffffffffff;//防你谷毒瘤
	for (int i = 1; i <= n; i ++)//阶段
	{
		int ti = 0;
		double Max = -0x7ffffffff;//防你谷毒瘤
		for (int j = i; j >= 1; j --)//方程
		{
			ti += w[j];
			if (ti > t) break;//如果当前的护卫队不可以一起过桥就结束循环,实际上复杂度没有 O(N^2)
			Max = max(s[j], Max);//多个护卫队一起过桥所耗的时间是最慢的那个护卫队所耗的时间
			f[i] = min(f[i], f[j - 1] + Max);
		}
	}
	printf("%.1lf\n", f[n] * 60);//防你谷毒瘤
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jvruo_shabi/article/details/108207960
今日推荐