题目链接: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;
}