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.
吉米在一家快递公司工作。他的工作是尽快把包裹送到顾客手中。他应在一天结束前,即24:00之前,根据订单将所有包裹送到客户手中。任何延误都应被处以以迟到时间为标准的重罚。
那是糟糕的一天。吉米的车坏了。当他修好它的时候。当时正好是24点。吉米当时唯一想的就是找到一个合适的方法来交付,把罚款降到最低。
他看了看地图,发现他现在的位置和他要去的所有地方都在一条环形路上。他可以把车顺时针或逆时针开到环行公路的任何地方。他想让你帮他找到减少罚款的最佳方法。
罚款描述如下:如果吉米迟到,他必须为每一个未送达的包裹每分钟支付一美元。

输入

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.
输入包含几个测试用例。每种情况的第一行包含一个整数N,不超过300,其中(N-1)是他必须送到的地方数。下面的N行描述了N个点,包括他的当前位置和他必须去的(N-1)个目的地。这N个点是根据它们在Jimmy当前位置上的位置顺时针描述的。每行由两个整数m和t组成。m是这个地方订购的包裹数量,第一行总是0,其他行总是正整数。t、 以分钟为单位,表示从这一点到下一点的时间(第(N-1)个目的地的下一点是Jimmy的当前位置)。
N=0的测试用例表示输入结束,不应该处理这个用例。

输出

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.
对于每个测试用例,您应该输出一行,其中只包含一个整数,这是Jimmy必须支付的最低罚款。您可以假设所有测试用例的答案都小于1000000000。

测试样例

样例1

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

样例2

4
0 1
300 1
1 500
100 1
0
606

来源

Beijing 2005 Preliminary
POJ2671

解答

#include <iostream>

#define MAXN 305
#define SUP 1000000000;
using namespace std;
int Num[MAXN];
int Time[MAXN];

int l[MAXN][MAXN];//l[i][j]表示站在i处要处理i到j最少需要赔的钱
int r[MAXN][MAXN];//r[i][j]表示站在j处要处理i到j最少需要赔的钱
int w[MAXN][MAXN];//w表示i和j之间货物个数
int clock_time[MAXN];//0到i点时间
int anti_clock_time[MAXN];//i到0点时间

void Init(int N)
{
    clock_time[0] = 0;
    for (int i = 1; i < N; i++)
    {//顺时针跑下去所需要的时间
        clock_time[i] = clock_time[i - 1] + Time[i - 1];
    }

    anti_clock_time[N] = 0;
    for (int i = N - 1; i >= 0; i--)
    {//逆时针跑下去所需要的时间
        anti_clock_time[i] = anti_clock_time[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] = 0;
                r[i][j] = 0;
            }
            else
            {
                l[i][j] = SUP;
                r[i][j] = SUP;
            }
        }
    }
}

int main()
{
    //freopen("E://test.txt", "r", stdin);
    while (true)
    {
        int N;
        cin >> N;
        if (N == 0)
        {
            break;
        }

        for (int i = 0; i < N; i++)
        {
            cin >> Num[i] >> Time[i];
        }
        Num[N] = Time[N] = 0;
        N++;
        Init(N);

        for (int k = 1; k < N; k++)
        {//跨度
            for (int i = 0; i + k < N; i++)
            {
                int j = i + k;
                l[i][j] = min(l[i + 1][j] + Time[i] * w[i + 1][j],
                              r[i + 1][j] + (clock_time[i] + anti_clock_time[j]) * w[i + 1][j]);
                r[i][j] = min(r[i][j - 1] + Time[j - 1] * w[i][j - 1],
                              l[i][j - 1] + (clock_time[i] + anti_clock_time[j]) * w[i][j - 1]);
            }
        }
        cout << min(l[0][N - 1], r[0][N - 1]) << endl;
    }
    return 0;
}

想法

在这里插入图片描述
现在来分析l[i][j]r[i][j]同理),即站在i处要处理i到j最少需要赔的钱,那么可以有两种情况:
①先走到i + 1,此时就变成了l[i + 1][j],又因为先走了Time[i]的时间(从ii + 1),所以i + 1到j的处理时间都要推迟Time[i],所以l[i][j] = min(l[i][j], l[i + 1][j] + time[i]*w[i + 1][j])
②先从外侧走到j,然后就是r[i + 1][j],而此时先花掉的时间就是clock_time[i] + anti_clock_time[j],所以l[i][j] = min(l[i][j], r[i + 1][j] + (clock_time[i] + anti_clock_time[j])*w[i + 1][j])

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhj12399

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值