题目链接:http://codeforces.com/problemset/problem/229/D
这个城市有n座塔,为了美观,需要后面的塔不能比前面的塔矮,所以需要你来整理,你的操作方式是可以把任意一个塔放到他相邻的一座塔上,组成一座新塔,
注意只能移到相邻的塔上,新塔还能继续移动,问你最少多少步可以完成
思路:
一开始我天真的以为是贪心,想在O(n)的复杂度上解决他,代码也写出来了,过了很多组数据,CF给后台,当我看那组我WA的数据的时候,我才意识到我的思路是完全错的,就扔掉了,过了好几个月才捡起来想了个DP的解法:
二维DP,dp[i][j]:i表示第i座塔移动的j步,他能达到的最矮的情况,dp不断更新,跑一遍O(n^2)能解决,
#include <bits/stdc++.h>
using namespace std;
int dp[5002][5002];//第i个塔,用了j步骤的高度,向前压,向后压
const int inf=0x7f7f7f7f;
class Solution
{
int n,a[5002];
public:
Solution(int _n):n(_n)
{
for(int i=0; i<n; ++i)
scanf("%d",&a[i]);
memset(dp,0x7f,sizeof(dp));//字节赋值
dp[0][0]=a[0];
}
void win()
{
for(int i=1; i<n; ++i) //枚举塔
for(int j=0; j<i; ++j) //枚举前点
{
if(dp[i-1][j] == inf) continue;
if(a[i] < dp[i-1][j])
{
dp[i][j+1]=min(dp[i-1][j]+a[i],dp[i][j+1]);//先直接加到前面,后面再决策他是否最优
int k=0,rp=a[i];//向后找
while(rp<dp[i-1][j])
rp+=a[(++k) + i];
if(rp<dp[i-1][j])//后面所以的值都加起来都没前面的高,这个情况应舍弃
continue;
dp[i+k][j+k]=min(rp,dp[i+k][j+k]);
}
else dp[i][j]=a[i];
}
for(int i=0; i<=5000; ++i)
if(dp[n-1][i]<inf)
{
printf("%d\n",i);
break;
}
}
};
int main()
{
int n;
while(scanf("%d",&n)==1)
{
Solution OMG(n);
OMG.win();//OMG必胜,S5冠军,加油!
}
return 0;
}