zoukankan      html  css  js  c++  java
  • 最大值最小化问题

    问题描述:

    把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值最小是多少?

    例如序列1 2 3 2 5 4划分为3个子序列的最优方案为 1 2 3 | 2 5 | 4,其中S(1),S(2),S(3)分别为6,7,4,那么最大值为7;

    如果划分为 1 2 | 3 2 | 5 4,则最大值为9,不是最小。

    问题分析:

    能否使m个连续子序列所有的s(i)均不超过x,则该命题成立的最小的x即为答案。该命题不难判断,只需贪心,每次尽量从左

    向右尽量多划分元素即可。

    我们把该问题转化为递归分治问题,类似于二分查找。首先取Sum和元素最大值的中值x,如果命题为假,那么答案比x大;

    如果命题为真,则答案小于等于x。问题得解,复杂度为O(n*logSum)

    代码:

    #include<iostream>
    #include<vector>
    
    using namespace std;
    
    int divide = 3;
    
    int main()
    {
        vector<int> a = { 9, 19, 15, 13, 13, 9, 14, 1, 1, 7 };
        int max = INT_MIN;
        int sum = 0;
        for (int i = 0; i < a.size(); i++)
        {
            if (max < a[i])
            {
                max = a[i];
            }
            sum += a[i];
        }
        int left = max;
        int right = sum;
        int min = INT_MAX;
        while (left < right)
        {
            int middle = (left + right) / 2;
            int m = 0;
            int n = 0;
            int i;
            for (i = 0; i < a.size(); i++)
            {
                m += a[i];
                if (m<=middle)
                    continue;
                m = a[i];
                n++;
            }
            n++;
            if (n <= divide)
            {
                if (middle < min)
                    min = middle;
                right = middle - 1;
            }
            else
                left = middle + 1;
        }
        cout << min << endl;
    }
  • 相关阅读:
    VS2010插件及快捷键设置
    在Windows程序中启用console输出-2016.01.04
    使用VAssistX给文件和函数添加注释-2015.12.31
    windows在远程桌面连接中使用命令行参数
    windows网络编程-2015.12.29
    grep使用
    linux程序调试常用命令
    vim使用笔记
    infusion度量金字塔数据解释
    MVc Forms Membership rolemanage 角色权限验证管理
  • 原文地址:https://www.cnblogs.com/chaiwentao/p/4483584.html
Copyright © 2011-2022 走看看