zoukankan      html  css  js  c++  java
  • 斜率优化

    斜率优化

    不应该是截距优化吗 雾

    其实就是个线性规划问题,附上别人比我讲的好系列

    要注意的是,每一次枚举,斜率都是在变化的,所以要枚举n次,而第i次枚举必须把i点加入凸包,并维护凸包的元素(表现为队列尾部出队)

    而斜率优化最最最最重要的大前提是你会写dp方程

    例题:玩具装箱

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e4+5;
    int n,L;
    long long a[N],sum[N],dp[N];
    int q[N*2];
    long long X(int i)
    {
    	return sum[i]+i+L+1;
    }
    double Y(int i)
    {
    	return dp[i]+X(i)*X(i);
    }
    double slope(int qx,int zx)
    {
    	return (Y(zx)-Y(qx))/(X(zx)-X(qx));
    }
    
    int main()
    {
    	scanf("%d %d",&n,&L);
    	for(int i=1;i<=n;i++)
    	{
    		int x;
    		scanf("%d",&x);
    		sum[i]=sum[i-1]+x;
    		a[i]=sum[i]+i;
    	}
    	dp[0]=0;
    	//手动队列更好使
    	int head,tail;
    	head=1;
    	tail=0;
    	q[++tail]=dp[0];
    	for(int i=1;i<=n;i++)
    	{
    		// head==tail 1个元素,head<tail两个元素,找第一个斜率大于直线的点
    		while(head<tail&&slope(q[head],q[head+1])<=2*a[i]) head++;
    		dp[i]=dp[q[head]]+(a[i]-X(q[head]))*(a[i]-X(q[head]));
    		//判断i点加入凸包,凸包的改变(表现为删掉斜率大于等于的点)
    		while(head<tail&&slope(q[tail-1],q[tail])>=slope(q[tail-1],i)) tail--;
    		q[++tail]=i;
    	}
    	printf("%lld
    ",dp[n]);
    	return 0;
    }
    

    例题:POJ2018 Best Cow Fences

    因为距离要大于等于L,所以从点L+1开始枚举,每次维护一个下凸包,因为答案单调性,暴力从对头取出点,判断i与队头的斜率更新答案,最后每次把i-L的点加入队列,维护下凸包。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    using namespace std;
    const int N=1e5+5,inf=1e9+6;
    double eps=1e-6;
    int n,L;
    long long sum[N];
    int q[N*2];
    double maxn;
    long long X(int i)
    {
    	return i;
    }
    double Y(int i)
    {
    	return sum[i];
    }
    double slope(int qx,int zx)
    {
    	return (Y(zx)-Y(qx))/(X(zx)-X(qx));
    }
    
    int main()
    {
    	scanf("%d %d",&n,&L);
    	for(int i=1;i<=n;i++)
    	{
    		int x;
    		scanf("%d",&x);
    		sum[i]=sum[i-1]+x;
    	}
    	//手动队列更好使
    	int head,tail;
    	head=1;
    	tail=0;
    	q[++tail]=0;
    	double maxn=-inf;
    	for(int i=L;i<=n;i++)
    	{
    		while(head<tail&&slope(q[head],q[head+1])<=slope(q[head],i)+eps)
    			head++;
    		
    		while(head<tail&&slope(q[tail-1],q[tail])>=slope(q[tail],i-L+1)+eps)
    			tail--;
    		q[++tail]=i-L+1;
    		double slo=slope(q[head],i);
    		// printf("???%d %d %lf %lf
    ",q[head],i,slope(q[head],i),maxn);
    		if(slo>maxn+eps)
    		{
    			maxn=slo;
    		}
    	}
    	printf("%lld
    ",(long long)(maxn*1000));
    	return 0;
    }
    
    $道路千万条,点赞第一条;阅读不规范,笔者两行泪$
  • 相关阅读:
    Linux线程同步方法
    Linux进程间通信:信号
    孤儿进程僵尸进程及其回收
    Linux守护进程
    Linux系统编程常见函数 (进程/线程)
    Linux系统编程常用函数 (文件/目录)
    C++实现贪吃蛇小游戏
    C++实现简易Vector类
    C++实现简易版字符串类
    《图解HTTP》读书笔记
  • 原文地址:https://www.cnblogs.com/cherrypill/p/14342700.html
Copyright © 2011-2022 走看看