• [POJ3612] Telephone Wire(暴力dp+剪枝)


    [POJ3612] Telephone Wire(暴力dp+剪枝)

    题面

    有N根电线杆,初始高度为h[i],要给相邻的两根连线。可以选择拔高其中一部分电线杆,把一根电线杆拔高(Delta H)的代价为(Delta H^2)。拔高后,要给相邻的电线杆连线,连线相邻两根电线杆操作的代价为(CDelta H),其中C是一个常量且已经给出。求最小总代价。

    分析

    考虑一个显然的dp,设(dp[i][j])表示前i根电线杆,第i根拔到高度j的最小代价,记H表示max(h[i])

    (dp[i][j]=min(dp[i][j],dp[i-1][k]+C imes |j-k|+(j-h[i])^2),k in [h[i-1],H)) 。这里k的意义是第i-1根电线杆的高度

    直接转移是(O(nH^2))的,但有一个很强的剪枝可以通过本题

    若我们固定i,j,考虑k对(dp[i-1][k]+C imes |j-k|+(j-h[i])^2)的影响,k对(dp[i-1][k])造成了((k-h[i-1])^2)的影响,又造成了(C imes |j-k|)的影响,总的影响应该是一个关于k的二次函数。而我们知道二次函数是有对称性和单调性的。我们从小到大枚举k,若(dp[i-1][k]+C imes |j-k|+(j-h[i])^2>dp[i][j]),说明k已经大于那个二次函数的对称轴了,之后的函数值只会更大,这个时候就可以停止枚举k

    代码

    //暴力出奇迹 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define INF 0x3f3f3f3f
    #define rg register
    #define maxn 100000
    #define maxh 100
    using namespace std;
    typedef long long ll;
    inline void qread(int &x){
    	x=0;
    	int sign=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') sign=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	x=x*sign;
    }
    
    int n,c,lim;
    int h[maxn+5]; 
    int dp[maxn+5][maxh+5];
    inline int abs(int x){
    	return x>=0?x:-x; 
    } 
    inline int min(int x,int y){
    	return x<=y?x:y; 
    }
    int main(){
    	qread(n);
    	qread(c);
    	lim=0;
    	for(rg int i=1;i<=n;i++){
    		qread(h[i]);
    		lim=max(lim,h[i]);
    	}
    	memset(dp,0x3f,sizeof(dp));
    	for(rg int j=h[1];j<=lim;j++){
    		dp[1][j]=(j-h[1])*(j-h[1]);
    	}
    	for(rg int i=2;i<=n;i++){
    		for(rg int j=h[i];j<=lim;j++){//注意不用从0开始 
    			int last=INF;
    			for(rg int k=h[i-1];k<=lim;k++){
    				int now=dp[i-1][k]+c*abs(j-k)+(j-h[i])*(j-h[i]);
    				if(dp[i][j]>now) dp[i][j]=now;
    				if(now>last) break;//由于代价是二次函数,找到最小值点就不用再找了 
    								   //这是很强的一个优化 
    				last=now;
    			}
    		}
    	}
    	int ans=INF;
    	for(rg int i=h[n];i<=lim;i++) ans=min(ans,dp[n][i]);
    	printf("%d
    ",ans);
    }
    
    
  • 相关阅读:
    Java hello/hi的简单的网络聊天程序
    案例分析:设计模式与代码的结构特性
    网络相关的命令工具研究报告
    如何提高程序员的键盘使用效率
    分析一套源代码的代码规范和风格并讨论如何改进优化代码
    用例建模Use Case Modeling
    结合工程实践选题调研分析同类软件产品
    领域建模
    SecureCRT 连接虚拟机Linux
    用css固定div层在页面顶部和底部(兼容IE6)
  • 原文地址:https://www.cnblogs.com/birchtree/p/11239879.html
Copyright © 2020-2023  润新知