UVa Problem 10201 Adventures in Moving: Part IV (搬家大冒险:第四部)

// Adventures in Moving: Part IV (搬家大冒险:第四部)
// PC/UVa IDs: 111108/10201, Popularity: A, Success rate: low Level: 3
// Verdict: Accepted
// Submission Date: 2011-10-19
// UVa Run Time: 0.024s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// 2020-04-21 再次提交,发现无法通过当前数据,应该是测试数据发生了变化,故修改了代码。
// 即可能有这样的测试数据:终点位于两个加油站中间而不是位于加油站上。
//
// [解题方法]
// 令到达第 i 个加油站时,剩余油量为 j 升时的最小花费为 cost[i][j],d[m][i] 为第 m 个加油站
// 和第 i 个加油站之间的距离,p[i] 为第 i 个加油站加 1 升油的费用,则有以下状态转移方程:
//
// cost[i][j] = min{cost[m][n] + ((n - d[m][i] >= j) ? 0 : (d[m][i] + j - n) * 
// p[i] | d[m][i] <= n, 1<= m < i}
//
// 顺便给出一组测试数据和 AC 程序得到的结果:
// 10
//
// 500
// 100 1
// 300 1
// 350 1
// 501 10
//
// 101
// 100 100
// 102 1
//
// 100
//
// 101
//
// 200
// 100 10
//
// 201
// 100 10
//
// 201
// 101 10
//
// 50
// 25 10
//
// 150
// 100 10
// 151 20
//
// 150
// 100 10
// 151 20
// 152 1
//
// AC 程序给出的结果:
// 950
//
// 299
//
// Impossible
//
// Impossible
//
// 2000
//
// Impossible
//
// Impossible
//
// 500
//
// 1500
//
// 618
//
// 注意第一组数据,UVa 中的测试数据应该没有包含这样的数据,在到达 501 公里时,没有再退回到 500
// 公里处。

#include <bits/stdc++.h>

using namespace std;

#define MAXN 110                // 最大加油站数量。
#define MAXL 201                // 最大剩余油量的升数。
#define MAXINT (1 << 30)

int kilometers[MAXN];           // 加油站距离起点的距离(单位:公里)。
int price[MAXN];                // 加油站每加 1 升油的费用(单位:10 美分)。
int cost[MAXN][MAXL];           // 在加油站 i 拥有剩余油量 j 时的最小花费。
int nstations;                  // 加油站总个数。

// 动态规划求花费的最小费用。
int dp(int end)
{
    // 初始时,置全部费用为最大值。
    for (int i = 0; i < nstations; i++)
        for (int j = 0; j < MAXL; j++)
            cost[i][j] = MAXINT;

    // 第 0 个加油站剩余油量为 100 升时,总费用为 0。
    cost[0][100] = 0;
    for (int i = 0; i < nstations - 1; i++)
        for (int j = 0; j < MAXL; j++)
            if (cost[i][j] < MAXINT)
            {
                // 计算从加油站 i,剩余油量为 j 升时到达下一个加油站 next 时剩余油量为 k 升时的最小费用。
                int next = i + 1;
                while ((kilometers[next] - kilometers[i]) <= j && next < nstations)
                {
                    // 计算剩余油量。若剩余油量大于等于 k 升,则不需加油,否则需要加油。
                    int remain = j - (kilometers[next] - kilometers[i]);
                    for (int k = 0; k <= remain; k++)
                        cost[next][k] = min(cost[i][j], cost[next][k]);
                    for (int k = remain + 1; k < MAXL; k++)
                        cost[next][k] = min(cost[i][j] + (k - remain) * price[next], cost[next][k]);
                    next++;
                }
            }

    int minCost = MAXINT;
    for (int i = 0; i < nstations; i++)
        for (int j = 0; j < MAXL; j++)
            if (cost[i][j] < MAXINT)
                if (kilometers[i] <= end && j >= (100 + end - kilometers[i]))
                    minCost = min(minCost, cost[i][j]);
    return minCost;
}

int main(int ac, char *av[])
{
    int cases, end;
    bool printStupidEmptyLine = false;
    string line;

    // 读入测例数。
    cin >> cases;
    cin.ignore();
    getline(cin, line);

    while (cases--)
    {
        // 读入终点和起点间的距离。
        cin >> end;
        cin.ignore(256, '\n');

        // 设置起点为一个虚拟加油站,加油价格为 0,因为不会在此虚拟加油站加油。
        nstations = 0;
        kilometers[nstations] = 0;
        price[nstations] = 0;
        nstations++;

        // 读取实际的加油站距离和价格。
        while (getline(cin, line), line.length())
        {
            istringstream iss(line);
            iss >> kilometers[nstations] >> price[nstations];
            nstations++;
        }

        // 输出空行。
        if (printStupidEmptyLine)
            cout << endl;
        else
            printStupidEmptyLine = true;

        // 判断是否可达,若可达则计算最小花费。
        int r = dp(end);
        if (r == MAXINT)
            cout << "Impossible" << endl;
        else
            cout << r << endl;
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值