• 洛谷P5929 [POI1999]地图


    洛谷题目链接

    零、题目原文

    一个人口统计办公室要绘制一张地图。

    由于技术的原因只能使用少量的颜色。两个有相同或相近人口的区域在地图应用相同的颜色。例如一种颜色 (k),则 (A(k)) 是相应的数,则有:

    在用颜色(k) 的区域中至少有一半的区域的人口不大于 (A(k))

    在用颜色(k) 的区域中至少有一半的区域的人口不小于 (A(k))

    区域颜色误差是该区域的人口与 (A(k)) 差的绝对值。累计误差是所有区域颜色误差的总和。我们要求出一种最佳的染色方案,使得累计误差最小。

    (10 < n < 3000)(2 ≤ m ≤ 10)
    人口数 (< 2^{30})

    一、简明题意

    (n) 个区域,每个区域人口是(a[i])(m) 种颜色,现在要对所有区域着色。

    (A(k)) 即是中位数。(因为有一半区域不大于或不小于,所以肯定不大于与不小于的个数相等,即为中位数)

    区间误差即为连续同样颜色区间的每个数与中位数的绝对值之和,累计误差即为所有区间误差之和。

    二、思路

    1、朴素转移

    这题题目都讲了区间,明显的区间DP......

    (f[i][j]) 表示考虑了前(i) 个区域,已经用了(j) 种颜色的最小误差

    则枚举 (k), (f[i][j]) 一定是从前k个区间的最小值再加上从(k+1)(i) 的区间误差,

    状态转移方程式:(f[i][j] = min(f[i][j], f[k][j - 1] + color(k + 1, i))) ,其中(color) 即为区间误差之和。

    时间复杂度:(O(N ^ 3M))

    很明显,这个巨大的复杂度会T飞,所以需要一些优化

    2、求值优化

    再思考优化(color) ,可以先前缀和(sum) 求出每一段的人口数,而中位数即为排好序后中间两个数的平均数。

    所以区间误差之和不难得出,可以得到以下(O(1)) 的柿子:

    (a[mid] * (mid - l) - sum[mid - 1] + sum[l - 1] - a[mid] * (r - mid) + sum[r] - sum[mid]) ,(其中mid即为中间那个位置,不是中位数!)

    所以可以把这一个柿子单独写个函数拉出来,可以将时间复杂度优化到(O(N ^ 2M))

    三、code

    注意开始需要先排序,这样求中位数可以优化。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3005;
    const int M = 15;
    int n, m;
    int f[N][M], sum[N], a[N];
    int color(int l, int r)
    {
    	int mid = (l + r) / 2;//求中位数的位置
    	return a[mid] * (mid - l) - sum[mid - 1] + sum[l - 1] - a[mid] * (r - mid) + sum[r] - sum[mid]; //O(1)优化
    }              
    int main()
    {
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> a[i];
    	}
    	sort(a + 1, a + n + 1);
    	for(int i = 1; i <= n; i++)
    	{
    		sum[i] = sum[i - 1] + a[i];//前缀和预处理
    	}
    	memset(f, 0x3f, sizeof f);//开始全赋最大值
    	f[0][0] = 0;
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= m; j++)
    		{
    			for(int k = 0; k < i; k++)
    			{
    				f[i][j] = min(f[i][j], f[k][j - 1] + color(k + 1, i));//转移方程
    			}
    		}		
    	}
    	cout << f[n][m];
    	return 0;
    }
    
  • 相关阅读:
    计算机网络面试小知识总结(转载)
    williamisnotme@gmail.com
    jdk1,8 HashMap
    Mybatis 为什么不要用二级缓存
    CPU,寄存器,一缓二缓.... RAM ROM 外部存储器等简介
    一级缓存,二级缓存
    mock单测
    java8函数式编程(转载)
    volatile解析
    JVM 技术分享(初级)
  • 原文地址:https://www.cnblogs.com/pjxpjx/p/13854320.html
Copyright © 2020-2023  润新知