关闭

从一个问题的多个算法看算法的优化

标签: 枚举优化
297人阅读 评论(0) 收藏 举报
分类:

题目:给定两个数列a1,a2,,anb1,b2,,bn,你可以用这两个数列来产生新数列c1,c2,,cn. 产生的方式是令ci=ai+biaibi. 用cmaxcmin分别表示c1,c2,,cn的最大值和最小值,求cmaxcmin的最小值. 每个aibi的取值都是-100 000 000到100 000 000范围内的整数.
算法一:
暴力穷举数列c的所有可能,看cmaxcmin能取得的最小值是多少. 因为每个ci有两种可能的取值,所以总共有2n个可能的数列,算法复杂度O(N2N).
算法二:
我们换个角度来想,算法一之所以复杂度高,是因为数列c的可能性太多了,那问题中有没有哪些值可能性并没有那么多,但只要我们枚举这些值就可以得到答案呢?有,比如cmaxcmin. 不管是cmax还是cmin,它们都只能取某个ci=ai+biaibi,因而都只有2n种取值可能. 这样我们就可以得到更好的算法,我们枚举cmaxcmin的所有可能取值(步骤1),然后判断对于每个i,ai+biaibi是否至少有一个落在[cmin, cmax]的范围内(步骤2). 步骤1的复杂度是O(N2),步骤2的复杂度是O(N),算法总复杂度O(N3). 程序如下:

#include <cstdio>

const int N = 100 + 10;
const int inf = 1000000000;

int A[N], B[N];
int n;

inline bool in_range(int left, int right, int x)
{
    return x >= left && x <= right;
}

bool check(int left, int right, int& d)
{
    int tmp, i;
    if (left > right)
    {
        tmp = left;
        left = right;
        right = tmp;
    }
    for (i=0; i<n; i++) if (!in_range(left, right, A[i] + B[i]) && !in_range(left, right, A[i] - B[i])) return false;
    d = right - left;
    return true;
}

int main()
{
    int res, t, d, i, j, k;
    scanf("%d", &t);
    while (t --)
    {
        scanf("%d", &n);
        for (i=0; i<n; i++) scanf("%d", &A[i]);
        for (i=0; i<n; i++) scanf("%d", &B[i]);
        if (n == 1)
        {
            printf("0\n");
            continue;
        }
        res = inf;
        for (i=0; i<n-1; i++)
            for (j=i+1; j<n; j++)
            {
                if (check(A[i] + B[i], A[j] + B[j], d) && d < res) res = d;
                if (check(A[i] + B[i], A[j] - B[j], d) && d < res) res = d;
                if (check(A[i] - B[i], A[j] + B[j], d) && d < res) res = d;
                if (check(A[i] - B[i], A[j] - B[j], d) && d < res) res = d;
            }
        printf("%d\n", res);    
    }
    return 0;
}

算法三:
我们再进一步考虑cmaxcmin是否都需要枚举?其实不需要,我们可以只枚举cmin,因为对于每个cmin,我们希望cmax尽可能小,所以其实对于每个ici肯定是取ai+biaibi中,在大于等于cmin的前提下的较小值. 因而对于枚举的每个cmin我们都可以O(N)时间内求出cmax. 算法总复杂度O(N2). 程序比算法二更加简洁.

#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100 + 10;
const int inf = 1000000000;

int A[N], B[N];
int n;

bool check(int left, int& d)
{
    int right, i;
    right = left;
    for (i=0; i<n; i++)
        if (A[i] + B[i] >= left && A[i] - B[i] >= left) right = max(right, min(A[i] + B[i], A[i] - B[i]));
        else if (A[i] + B[i] >= left) right = max(right, A[i] + B[i]);
        else if (A[i] - B[i] >= left) right = max(right, A[i] - B[i]);
        else return false;
    d = right - left;
    return true;    
}

int main()
{
    int res, t, d, i, j;
    scanf("%d", &t);
    while (t --)
    {
        scanf("%d", &n);
        for (i=0; i<n; i++) scanf("%d", &A[i]);
        for (i=0; i<n; i++) scanf("%d", &B[i]);
        res = inf;
        for (i=0; i<n; i++)
        {
            if (check(A[i] + B[i], d) && d < res) res = d;
            if (check(A[i] - B[i], d) && d < res) res = d;
        }
        printf("%d\n", res);
    }
    return 0;
} 

算法四:
前面的算法,枚举c也好,枚举cmincmax,其实都是从局部出发的,我们可以试试从宏观的角度来思考这个问题. 宏观来看,就是数轴上有2N个点,每个点会属于某个i,我们希望在数轴上选最短的一段,使得这一段内的点分属于1到N,或者说使得对于每个i,ai+biaibi至少有一个在这一段中. 于是我们可以用O(N)扫描的方法,来解决这个问题. 因为用到排序,所以算法的总复杂度是O(NlogN). 程序如下:

#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100 + 10;
const int inf = 1000000000;

struct ITEM
{
    int val, id;
    ITEM(int val=0, int id=0):val(val), id(id){}
};

int A[N], B[N], cnt[N];
ITEM C[2*N];
int n;

bool operator < (const ITEM& a, const ITEM& b)
{
    return a.val < b.val;
}

int main()
{
    int res, t, s, i, j;
    scanf("%d", &t);
    while (t --)
    {
        scanf("%d", &n);
        for (i=0; i<n; i++) scanf("%d", &A[i]);
        for (i=0; i<n; i++) scanf("%d", &B[i]);
        for (i=0; i<n; i++)
        {
            C[i*2] = ITEM(A[i] + B[i], i);
            C[i*2+1] = ITEM(A[i] - B[i], i);
            cnt[i] = 0;
        }
        sort(C, C + 2 * n);
        s = 0;
        for (i=0; i<2*n; i++)
        {
            cnt[C[i].id] ++;
            if (cnt[C[i].id] == 1) s ++;
            if (s == n) break;
        }
        j = 0;
        for (; cnt[C[j].id]==2; j++) cnt[C[j].id] --; 
        res = C[i].val - C[j].val;
        for (i++; i<2*n; i++)
        {
            cnt[C[i].id] ++;
            for (; cnt[C[j].id]==2; j++) cnt[C[j].id] --;
            res = min(res, C[i].val - C[j].val);
        }
        printf("%d\n", res);
    }
    return 0;
} 

总结一下,我们设计和优化算法,常见的思路一个是尽可能的减少可能性,可能性越少,需要枚举的就越少;一个是多变换看待问题的角度,有时换个角度就能更容洞悉问题的本质.

2
0
查看评论

实用优化算法(一)准备和概念

问题的分类:组合问题和数值问题 组合(Combinatorial)优化问题定义在一个有限的离散的问题空间里。比如:位流、元素置换、课程选择等。 数值(Numerical)优化问题定义在数字领域或者涉及实值变量。比如:求的数学方程式、股票预测、飞机机翼设计等。 优化算法(Optimization...
  • u010053421
  • u010053421
  • 2015-03-17 01:45
  • 347

智能优化算法总结

优化算法有很多,经典算法包括:有线性规划,动态规划等;改进型局部搜索算法包括爬山法,最速下降法等,模拟退火、遗传算法以及禁忌搜索称作指导性搜索法。而神经网络,混沌搜索则属于系统动态演化方法。梯度为基础的传统优化算法具有较高的计算效率、较强的可靠性、比较成熟等优点,是一类最重要的、应用最广泛的优化算法...
  • Sinde1992
  • Sinde1992
  • 2015-12-15 21:56
  • 13389

优化算法的比较,选择

来源知乎:http://www.zhihu.com/question/20822481 梯度和最小二乘的区别: 1.本质相同:两种方法都是在给定已知数据(independent & dependent variables)的前提下对dependent variables算出出一个一般性的...
  • Ben_Ben_Niao
  • Ben_Ben_Niao
  • 2015-08-06 12:53
  • 1075

km算法+slack优化 poj3565

km算法在百度上讲的很清楚讲一些针对这道题的有n只蚂蚁要吃n个苹果,求总路径和最小,且不交叉的方案网上有很多人说是计算几何题其实,研究一下题意可以得出很重要的性质————最优方案一定不交叉。根据三角形不等式adad+bc因此,我们只需要构造二分图,求最小权和匹配将所有蚂蚁看做一个集合,所有苹果看做一...
  • huyuncong
  • huyuncong
  • 2011-04-16 12:58
  • 2210

数据结构与算法之Josephus问题(用Java解决)

Josephus问题是下面的游戏:N个人编号从1到N,围坐成一个圆圈。从1号开始传递一个热土豆,。经过M次传递后拿着热土豆的人被清除离座,围坐的圆圈紧缩,由坐在被清除的人后面的人拿起热土豆继续进行游戏。最后剩下的人取胜。
  • heyahuihh
  • heyahuihh
  • 2017-01-05 18:23
  • 1016

动态规划算法之资源分配问题及其空间优化方案

资源分配问题:某厂根据计划安排,拟将n台相同的设备分配给m个车间,各车间获得这种设备后,可以为国家提供盈利Ci j(i台设备提供给j号车间将得到的利润,1≤i≤n,1≤j≤m)。问如何分配,才使国家得到最大的盈利? 一、算法思想 1、  动态规划的最优性    ...
  • iamubbTing
  • iamubbTing
  • 2017-01-13 15:53
  • 4595

素数算法的优化之路

素数算法的优化之路
  • s634772208
  • s634772208
  • 2015-06-02 12:49
  • 1238

算法中的优化问题(optimization problem)

和多数算法不同的是,有些问题的答案不只一个,而是需要在多个答案中,按照一定标准选出“最佳”答案,这类问题就统称为“优化问题”(optimization problem)。
  • lanchunhui
  • lanchunhui
  • 2016-09-05 22:28
  • 676

问题与不足(KNN算法)

问题与不足 论文题目:k-NearestNeighbors on Road Networks: A Journey in Experimentation and In-MemoryImplementation  一、主要内容 该论文主要研究了K Nearest Neighbor算法在...
  • hit_buxiaoyu
  • hit_buxiaoyu
  • 2016-12-21 13:10
  • 776

ICP迭代最近点优化

点云之间的局部配准问题采样迭代最近点算法(IteratedClosest Points, ICP),ICP算法因为其思想简单,精度高等特点成为了局部配准的主流算法。 迭代最近点算法(ICP)顾名思义,就是采用迭代优化的思想以空间距离作为匹配点的选择依据,通过不断调整点云的位姿使得匹配点之间距离累计最...
  • my_lord_
  • my_lord_
  • 2017-07-25 09:30
  • 225
    个人资料
    • 访问:302次
    • 积分:42
    • 等级:
    • 排名:千里之外
    • 原创:1篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档