UVa 10201 Adventures in Moving(简单DP)

题意:

有一辆车,原始装有100L汽油,到达距离为d的目的地,中间有x个加油站,每升油的价格为p。

汽车每跑一公里耗油1L,求到达目的地油箱仍然有100L的最小花费。

思路:

动归方程算是简单的,主要是要思考清楚,在第i个加油站加不加油,如果加油加k升的最小花费。

dp[i, j]表示在第i个加油站油箱有j升油的最小花费:

1. 在i站不加油 dp[i, j] = dp[i-1, j+di]; di为i-1到i的距离

2. 在i站加k升油 dp[i][j] = min(dp[i][j], dp[i-1][j-k+di] + k * p[i]);

初始状态为:dp[0, 100] = 0 其它的都是不可到达状态,赋值int_max

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;

int dp[110][210];
int d[110], p[110];
char str[100];
int dis, n;

void init_input()
{
    gets(str);
    sscanf(str, "%d", &dis);
    n = 0;
    d[0] = 0;
    while (gets(str) != NULL)
    {
        if (str[0] == '\0')
            break;
        ++n;
        sscanf(str, "%d %d", &d[n], &p[n]);

        if (d[n] > dis) --n;
    }
}

void solve_dp()
{
    for (int i = 0; i <= n; ++i)
        for (int j = 0; j <= 200; ++j)
            dp[i][j] = INT_MAX;
    dp[0][100] = 0;

    for (int i = 1; i <= n; ++i)
    {
        int w = d[i] - d[i-1];

        for (int j = 0; j + w <= 200; ++j)
            if (dp[i-1][j+w] != INT_MAX)
                dp[i][j] = dp[i-1][j+w];

        for (int j = 0; j <= 200; ++j)
            for (int k = 0; k <= j; ++k)
                if (j-k+w <= 200 && dp[i-1][j-k+w] != INT_MAX)
                    dp[i][j] = min(dp[i][j], dp[i-1][j-k+w] + k * p[i]);
    }

    if (100 < dis - d[n] || dp[n][100+dis-d[n]] == INT_MAX)
        printf("Impossible\n");
    else
        printf("%d\n", dp[n][100+dis-d[n]]);
}

int main()
{
    int cases;
    gets(str);
    sscanf(str, "%d", &cases);
    gets(str);
    while (cases--)
    {
        init_input();
        solve_dp();
        if (cases)
            printf("\n");
    }
    return 0;
}

 

posted @ 2012-11-21 12:06  kedebug  阅读(657)  评论(0编辑  收藏  举报