Codeforces Round #500 (Div. 2) [based on EJOI]--E. Hills

题目链接:http://codeforces.com/contest/1013/problem/E

题意:给你n座山,你需要在山上造房子,房子只能造在比两边的山都要高的山上(如果两边有山的话),你需要造[n/2](向上取整)座房子,你可以叫挖掘机在任意一座山上一小时铲低一米,输出造第i座房子的最短时间。

思路:一开始我想用优先队列搞一搞,因为当n为奇数的时候造房子的山就确定了,(只能在1,3,5,7···),所以只需用优先队列维护这个位置所需的最短时间。但当n为偶数的时候,造房子的山就不确定了,gg。然后又不知道怎么做了,菜的一笔。没错,我又去看了大佬的代码,发现可以用dp做。做法如下:

dp[i][j][z]表示在(1,i)内建j个房子,是(z=1)否(z=0)在i处建

代码如下:

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<functional>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<unordered_map>
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
using namespace std;
#define MAXN 100010
int dp[5005][2505][2];
int a[5005];
int ma(int x,int y)
{
    if(x>y)return 0;
    return y-x+1;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    a[0]=0;
    int k=n/2;
    if(n%2==1)k++;
    memset(dp,inf,sizeof(dp));
    dp[1][0][0]=0;dp[0][0][0]=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<=k;j++)
            for(int z=0;z<2;z++)
            {
               if(dp[i][j][z]==inf)continue;//此状态不合法
               if(z==0)
               {
                   dp[i+1][j][0]=min(dp[i][j][0],dp[i+1][j][0]);
                   dp[i+1][j+1][1]=min(dp[i+1][j+1][1],dp[i][j][0]+ma(a[i+1],a[i]));
               }
               else
               {
                   dp[i+1][j][0]=min(dp[i+1][j][0],dp[i][j][z]+ma(a[i],a[i+1]));
                   dp[i+2][j+1][1]=min(dp[i+2][j+1][1],dp[i][j][z]+ma(min(a[i+2],a[i]),a[i+1]));
               }
            }
    for(int j=1;j<=k;j++)
    {
        if(j!=1)printf(" ");
        printf("%d",min(dp[n][j][0],dp[n][j][1]));
    }
    printf("\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dhydye/article/details/81321427
今日推荐