zoukankan      html  css  js  c++  java
  • HDU-2829 Lawrence(斜率DP)

    题意:有一排仓库,每个仓库都有个价值,可以炸掉两个仓库之间的铁路,如果仓库按顺序是4---5---1---2,那么整个路段的总价值为4 * 5 + 4 * 1 + 4 * 2 + 5 * 1 + 5 * 2 == 49,我们可以炸掉5---1之间的路段,那么总价值将变为4 * 5 + 1 * 2 == 22,求炸掉路段的总价值的最小值。

    分析:假设w[a][b]为a仓库到b仓库的总价值,那么w[a][b]的DP方程为(w[1][i] = w[1][k] + w[k + 1][i] + (v[1] + v[2] + ... v[k]) * (v[k + 1] + ... + v[i])),可以得到(w[k + 1][i] = w[1][i] - w[1][k] - sum[k] * (sum[i] - sum[k])),也就是第k个仓库到第i个仓库的总价值。我们定义f[i][j]为前i个仓库分成j批的总价值,那么(f[i][j] = min(f[k][j - 1] + w[1][i] - w[1][k] - sum[k] * (sum[i] - sum[k]))(0 <= k < i)),那么我们通过变形,得到(f[k][j - 1] - w[1][k] + sum[k]^{2} = f[i][j] - w[1][i] + sum[k] * sum[i]),我们假设(f[k][j - 1] - w[1][k] + sum[k]^{2}为y)(sum[i]为k),那么可以得到(y = k * sum[k] + f[i][j] - w[1][i]),这样我们就可以利用凸包进行优化。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    const int N = 1005;
    int d[N];
    int sum[N];
    int w[N];
    int f[N][N];
    int q[N];
    
    int get_y(int k, int j)
    {
    	return f[j - 1][k] - w[k] + sum[k] * sum[k];
    }
    
    int main()
    {
    	int n, m;
    	while (scanf("%d%d", &n, &m) != EOF)
    	{
    		if (n == 0 && m == 0) break;
    		for (int i = 1; i <= n; ++i) scanf("%d", &d[i]);
    
    		for (int i = 1; i <= n; ++i)
    		{
    			sum[i] = sum[i - 1] + d[i];
    			w[i] = w[i - 1] + sum[i - 1] * d[i];
    		}
    
    		for (int i = 1; i <= n; ++i) f[0][i] = w[i];
    
    		//分成m批
    		for (int j = 1; j <= m; ++j)
    		{
    			int hh = 0, tt = 0;
    			q[0] = 0;
    			//前i个仓库分成j批的最小值
    			for (int i = 1; i <= n; ++i)
    			{
    				while (hh < tt && (get_y(q[hh + 1], j) - get_y(q[hh], j)) <= sum[i] * (sum[q[hh + 1]] - sum[q[hh]])) ++hh;
    				int k = q[hh];
    				f[j][i] = f[j - 1][k] + w[i] - w[k] - sum[k] * (sum[i] - sum[k]);
    				while (hh < tt && (get_y(q[tt], j) - get_y(q[tt - 1], j)) * (sum[i] - sum[q[tt]]) >= (get_y(i, j) - get_y(q[tt], j)) * (sum[q[tt]] - sum[q[tt - 1]])) --tt;
    				q[++tt] = i;
    			}
    		}
    
    		printf("%d
    ", f[m][n]);
    
    	}
    
    
    
    	return 0;
    }
    
  • 相关阅读:
    setprecision和setiosflags函数
    free和malloc的使用
    栈内存与堆内存
    一个教科书一般的“空指针”错误
    孙鑫教程第三章小测试程序
    向函数传递结构体信息
    指针(二)
    指针(一)
    cocos2d场景和UIViewController视图的切换
    UIScrollView 原理详解
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13369261.html
Copyright © 2011-2022 走看看