nyoj 1070 诡异的电梯 简单dp

题目:
新的宿舍楼有 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个数字表示每个学生想要停的楼层。

分析:
d[i]表示走到第i层的最少费用,状态转移方程d[i]=min(d[i-1]+B*a[i],d[i-2]+v*a[i-1]);
表示从到第i层,可以有两种选择,如果在第i-1层停了,那么就不能在第i层停了,所以在第i层的人要从第i-1层走上去,如果在第i-2层停了,那么第i-1层的人可以选择从第i-2层上去或者从第i层下去,其中 v=min(A,B)

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int d[N],a[N];
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        int n,m,A,B;
        scanf("%d%d%d%d",&n,&m,&A,&B);
        memset(a,0,sizeof(a));
        for(int i=0;i<m;i++){
            int x;scanf("%d",&x);
            a[x]++;
        }
        int ans;
        if(n==1||n==2){
            ans=0;
        }
        else{
            int v=min(A,B);
            for(int i=3;i<=n;i++){
                d[i]=min(d[i-1]+B*a[i],d[i-2]+v*a[i-1]);
            }
        }
        ans=d[n];
        printf("Case %d: %d\n",cas,ans);
    }return 0;
}

你可能感兴趣的:(dp)