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;

}

 

你可能感兴趣的:(uva)