贪心问题的应用之点点滴滴二三事儿(摘自《算法设计与实践》)

贪心的基本知识就不说了...比较基础的

贪心算法的基本步骤:

1、从问题的某个初始解出发。

2、采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或者规模。


贪心算法应用于:

1、引导问题。最基本的就是HDU 1009 FatMouse' Trade(水题小能手hhhhh)。

2、时间序列问题。(觉得其实就是活动安排问题。)

具体解释下:

已知N个事件的发生时刻和结束时刻(事件已经按照结束时刻升序排序)。一些在时间上没有重叠的事件,可以构成一个事件序列。

事件序列包含的时间数目,称为该事件序列的长度。

试找出一个最长的事件序列。

分析:

具体的分析,本人觉得比较详细易懂的。(戳)

不妨用Begin[I]和End[I]表示事件I的开始时刻和结束时刻,则原题的要求就是找一个最长的序列a1 < a2 < ...... < an,满足:

Begin[a1] < End[a1] <= ...... <= Begin[an] < End[an].

可以证明,如果在可能的事件a1 < a2 < a3 < ...... < an中选取时间上不重叠的最长序列,那么一定存在一个包含a1(结束最早)的最长序列。


根据这种题,书上给出的样题是:HDU 2037 今年暑假不AC

呃......其实某破航也给出了一道题:忙碌的Nova君

<两道题的解法几乎相同......>

给出某官方的代码【注意对上一个时间的记录和处理。】(逃

#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;

struct inp
{
    int x,y;
}node[105];

bool cmp(inp a, inp b)
{
    return a.y < b.y;
}

int main(){
    int i,j,s,n;
    while(scanf("%d", &n) && n)
    {
        for(i = 0; i < n; i++)
            cin >> node[i].x >> node[i].y;
        sort(node, node + n, cmp);
        j = 0;
        s = 1;
        for(i = 0; i < n; i++)
        {
            if(node[i].x >= node[j].y)
            {
                s++;
                j = i;
            }
        }
        printf("%d\n", s);
    }
	return 0;
}

3、区间覆盖问题。

具体描述:

用i表示x轴上座标为[ i - 1, i ]的区间(长度为1),并给出M(1 <= M <= 200) 个不同的整数,表示M个这样的区间。

现在让你画几条线段覆盖住所有的区间,条件是每一条线段可以任意长,但是要求所画线段之和最小,并且线段的数目不超过N。

分析:

如果N>= M,那么显然用M条长度为1 的线段可以覆盖住所有的区间,所求的线段总长为M。

如果N = 1,那么显然所需的线段总长为i(max) - i(min) + 1。

如果N = 2,那么相当于是在N = 1的情况下从某一个地方断开。

如果N = k,那么从间隔最大的两个部分断开。

给出书本上面的样题:HDU 1051 Wooden Sticks(需要使用到标记值,颇费脑子)

    HDU 1050 Moving Tables(这道题可以用贪心和树状数组来解,树状数组还没有涉及,但是我会回来的......)

    HDU 2570 迷瘴 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章