描述
新的宿舍楼有 N(1≤N≤100000) 层 and M(1≤M≤100000)个学生. 在新的宿舍楼里, 为了节约学生的时间也为了鼓励学生锻炼身体, 所以规定该宿舍楼里的电梯在相邻的两层之间是不会连续停下(即,如果在第2层停下就不能在第3层停下。).所以,如果有学生在相邻的两层之间要停下, 则其中的一部分学生必须选择走楼梯来代替。规定:一个人走下一层楼梯的花费为A,走上一层楼梯的花费为B。(1≤A,B≤100)现在请你设计一个算法来计算出所有学生走楼梯花费的最小费用总和。 所有的学生一开始都在第一层,电梯不能往下走,在第二层的时候电梯可以停止。

输入
输入有几组数据T。T(1≤T≤10)
每组数据有N (1≤N≤100000),M(1≤M≤100000),A,B(1≤A,B≤100)。
接下来有M个数字表示每个学生想要停的楼层。

输出
输出看样例。
样例输入
1
3 2 1 1
2 3
样例输出
Case 1: 1

一个简单的一维dp,为了得到最短时间费用,需要考虑到隔一层下与隔两层下的情况,其中隔两层下的情况又分为四种,具体代码如下,注释很清楚,应该很容易理解的!

#include <stdio.h>
#include <string.h>
#define MAXSIZE 100005
#define MIN(a, b) a < b ? a : b

int main(int argc, const char * argv[])
{
    int T;
    int N, M, A, B;
    int to;
    int wantTo[MAXSIZE];
    int i, key = 0;
    int cost[MAXSIZE];

    scanf("%d", &T);
    while (T--)
    {
        key++;
        memset(wantTo, 0, sizeof(wantTo));
        memset(cost, 0x3F, sizeof(cost));

        scanf("%d %d %d %d", &N, &M, &A, &B);
        for (i = 0; i < M; i++)
        {
            scanf("%d", &to);
            wantTo[to]++;
        }

        int temp;
        int min = MIN(A, B);
        cost[0] = cost[1] = cost[2] = 0;
        for (i = 3; i <= N; i++)
        {
            cost[i] = MIN(cost[i], cost[i - 2] + wantTo[i - 1] * min);
            /* + i层 + ⬆️ + (i - 1)层 + ⬇️ + (i - 2)层 */

            if (i - 3 > 0)
            {
                temp = MIN(wantTo[i - 1] * A + wantTo[i - 2] * 2 * A, wantTo[i - 1] * 2 * B + wantTo[i - 2] * B);
                /* + i层 + ⬆️ / + (i - 1)层 + ⬆️⬆️ / ⬇️⬇️ + (i - 2)层 + / ⬇️ + (i - 3)层 */

                temp = MIN(temp, wantTo[i - 1] * A + wantTo[i - 2] * B);
                /* + i层 + ⬆️ + (i - 1)层 + (i - 2)层 + ⬇️ + (i - 3)层 */

                temp = MIN(temp, wantTo[i -1] * 2 * B + wantTo[i - 2] * 2 * A);
                /* + i层 + (i - 1)层 + ⬇️⬇️⬆️⬆️ + (i - 2)层 + (i - 3)层 */

                cost[i] = MIN(cost[i], cost[i - 3] + temp);
            }
        }

        printf("Case %d: %d\n", key, cost[N]);
    }

    return 0;
}