【BZOJ 1592】[Usaco2008 Feb]Making the Grade 路面修整 dp优化之转移变状态

本文介绍了一种通过离散化处理和状态转移的方法来解决特定类型的问题。使用该方法可以将复杂的状态空间简化,从而使得问题求解更加高效。文章详细解释了如何构建状态转移方程,并给出了具体的实现代码。

我们感性可证离散(不离散没法做),于是我们就有了状态转移的思路(我们只考虑单不减另一个同理),f[i][j]到了第i块高度为j的最小话费,于是我们就可以发现f[i][j]=Min(f[i-1][k])+|a[i]-j|(k<=j),于是我们的思路就去了各种数据结构…….然后我们发现对于这些转移就是在记录小于等于,那么我们直接带状态里体现这一点就可以了,而不是在转移的时候,我们f[i][j]表示到了第i个点小于等于j的高度的最小花费,这样我们就n^2了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2010
using namespace std;
inline int read()
{
  register int sum=0;register char ch=getchar();
  while(ch<'0'||ch>'9')ch=getchar();
  while(ch>='0'&&ch<='9')sum=(sum<<1)+(sum<<3)+ch-'0',ch=getchar();
  return sum;
}
int a[N],f[N][N],ans,n,pos[N],len,Hash[N];
int comp(const int x,const int y){
  return a[x]<a[y];
}
inline int Min(int x,int y){
  return x<y?x:y;
}
inline int Abs(int x){
  return x<0?-x:x;
}
inline int get_Min(){
  memset(f,0x7f,sizeof(f));register int ans=0x7fffffff;
  for(register int i=1;i<=len;i++)f[1][i]=Min(f[1][i-1],Abs(Hash[i]-Hash[a[1]]));
  for(register int i=2;i<=n;i++)
    for(register int j=1;j<=len;j++)
      f[i][j]=Min(f[i][j-1],f[i-1][j]+Abs(Hash[j]-Hash[a[i]]));
  for(register int i=1;i<=len;i++)ans=Min(ans,f[n][i]);
  return ans;
}
inline int get_Max(){
  memset(f,0x7f,sizeof(f));register int ans=0x7fffffff;
  for(register int i=1;i<=len;i++)f[1][i]=Min(f[1][i+1],Abs(Hash[i]-Hash[a[1]]));
  for(register int i=2;i<=n;i++)
    for(register int j=len;j>0;j--)
      f[i][j]=Min(f[i][j+1],f[i-1][j]+Abs(Hash[j]-Hash[a[i]]));
  for(register int i=1;i<=len;i++)ans=Min(ans,f[n][i]);
  return ans;
}
int main(){
  n=read();for(register int i=1;i<=n;i++)a[i]=read(),pos[i]=i;
  sort(pos+1,pos+n+1,comp);
  for(register int i=1;i<=n;i++)
    if(i==1||a[pos[i]]!=a[pos[i-1]])Hash[++len]=a[pos[i]],a[pos[i]]=len;
    else a[pos[i]]=len;
  printf("%d",Min(get_Min(),get_Max()));
}

 

转载于:https://www.cnblogs.com/TSHugh/p/7288914.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值