zoukankan      html  css  js  c++  java
  • poj3666 making the grade

    题意:给定长度为n(1<=n<=2000)的序列,将原序列变为单调不降或者单调不增的,求最小代价。这儿的代价定义为:设新序列为c,代价=|a1-c1|+|a2-c2|+...+|an-cn|

     

    这题看完题解也愣了好久,主要是状态设计的挺奇怪,而且一开始没弄懂怎么把3个循环优化成2个的。以单调不下降为例子(单调不增同理)。首先可以脑补,存在某种最优解序列,新序列中的数都是原序列中的数(严格证明鸽了......)。考虑状态f[i][j]表示完成了前i个数的构造,且把第i个数ai变成第j小的数bj,所需要的最小代价。那么有转移方程:f[i][j]=min(f[i-1][k])+abs(a[i]-b[j]),这儿数组b是a的升序排列(单调不降的情况),然后1<=k<=j(要保证把ai变成第j小的时候,构造的序列仍然单调不降)。看上去要用3重循环?但n<=2000复杂度就炸了。其实只要一边更新min(f[i-1][k])一般算当前的f[i][j]就行。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=20+10;
    bool cmp(int a,int b)
    {
    	return a>b;
    }
    int a[maxn],b[maxn],f[maxn][maxn];
    int n,i,j,k,t,ans1,ans2;
    int dp()
    {
    	int ans;
    	for (i=1;i<=n;i++) f[1][i]=abs(b[i]-a[1]);
    	for (i=2;i<=n;i++)
    	  {
    	  	int mmin=1<<31-1;
    	  	for (j=1;j<=n;j++)
    	  	  {
    	  	  	mmin=min(mmin,f[i-1][j]);
    	  	  	f[i][j]=mmin+abs(a[i]-b[j]);
    			}
    	  }
    	ans=1<<31-1;
    	for (i=1;i<=n;i++) ans=min(ans,f[n][i]);
    	return ans;
    }
    int main()
    {
    	cin>>n;
    	for (i=1;i<=n;i++) 
    	  {
    	  	cin>>a[i];b[i]=a[i];
    	  }
    	sort(b+1,b+n+1);ans1=dp();
    	sort(b+1,b+n+1,cmp);ans2=dp();
    	cout<<min(ans1,ans2)<<endl;
    	return 0;
    }
    

      

  • 相关阅读:
    tomcat请求流程浅解
    jdk8为啥lambda表达式建议你用冒号形式调用方法
    打印目录树形结构
    类斐波那契数列的java实现
    sping boot 如何将外部引入的jar包打到fat jar里面
    java多线程之生产者消费者
    Hadoop、Hbase、ZooKeeper的搭建
    java 静态代码块、构造代码块、构造函数调用顺序
    MyBatis的 or 和and 问题
    mysql
  • 原文地址:https://www.cnblogs.com/edmunds/p/12306923.html
Copyright © 2011-2022 走看看