贪心算法

——主要参考了中国大学MOOC程序设计与算法(二)算法基础课程的内容

贪心算法是指从问题的初始状态出发,通过多次的贪心选择,最终得到整个问题的最优解。贪心算法通常只考虑当前局部最优的策略,最终得到全局的最优解。

在实际问题中,贪心策略通常会将问题切分成不同的阶段,并通过一系列的贪心选择来得到一个问题的最优解。而每次选择都是当前状态的一种最优选择,即贪心选择,然后问题被转化为一个形式相同的子问题。为了最终可以得到最优解,贪心问题需要满足最优子结构和贪心选择的性质。最优子结构是指,一个问题的最优解包含其子问题的最优解,如A->B->C的最短路径中A->B也是最短的;贪心选择性质是指所求的问题的整体最优解可以通过一系列局部最优的选择来达到,这两点就保证了贪心策略可以达到最优解。

对于一个具体的贪心问题,在确定贪心选择之后,可以将问题转化为规模更小的子问题,同时也需要证明该贪心策略的正确性,常用的方法包括数学归纳法等,通过对算法步骤或者问题规模的划分,叙述一个正确的命题,然后对于不同阶段进行归纳,证明每一步贪心选择的正确性,从而证明整个贪心策略的正确性。

在实际贪心算法的设计过程中,首先要将问题转化为多步判断,整个序列对应问题本身的最优解,而子序列对应子问题的解;然后通过设计贪心选择,将原问题规约成子问题的解。在这里,如何设计贪心选择,并证明其正确性就成了贪心算法的核心。

建立雷达——贪心算法例题

Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.

We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.

image.png

这个题目难就难在不好分析,关键点在于先将小岛映射到X轴(雷达的坐标范围),将问题转化为在X轴上找N个点,覆盖掉映射的多条线段。贪心的选择也比较简单,先把小岛按X的左边界排序,再在左边放一个雷达(位置没有确定),然后看它能够覆盖到最右边的哪个位置。然后就重复这个动作,直到所有的小岛都遍历完了。下面给出代码:

#include
#include
#include
#include
using namespace std;

//记录小岛的坐标映射到x轴的左右距离
struct point
{
    double left;
    double right;
};
int Index;//记录测试的次数
int N;//小岛的数量
int D;//雷达的半径
int R;//雷达的数量
point Isle[1000];//记录每个小岛的x轴左右距离

bool operator<(const point& p1, const point& p2){
    return p1.left < p2.left;
}



int main(){
    Index = 1;
    cin >> N >> D;
    while (N != 0 && D != 0){
        bool flag = false;
        memset(Isle, 0, sizeof(Isle));//初始化小岛
        R = 1;//雷达的数量开始为0
        for (int i = 0; i < N; i++){
            double x, y;
            cin >> x >> y;
            if (y>D){
                flag = true;
            }
            double l = sqrt(D*D - y*y);
            Isle[i] = point{ x - l, x + l };
        }
        sort(Isle, Isle + N);
        double first = Isle[0].right;//第一个没覆盖的点
        for (int i = 0; i < N; i++){
            if (Isle[i].left <= first){
                first = min(Isle[i].right, first);
            }
            else{
                first = Isle[i].right;
                R++;
            }
        }
        if (flag){
            R = -1;
        }
        cout << "Case " << Index << ": " << R << endl;
        Index++;
        cin >> N >> D;
    }
    return 0;
}

田忌赛马——贪心算法例题

题目大概就不用叙述了,赢了200,平局0,输了-200。输入是先给马的数量,在给田忌的马的速度和齐王马的速度。这个题目的难点还是在于贪心的选择,下面直接给出代码,因为代码注释写得很清楚。

#include
#include

using namespace std;
#define MAX 1000

int N;//马的数量
int T[MAX];//田忌马的速度
int Q[MAX];//齐威王马的速度

int main() {
    cin>>N;
    while(N!=0) {
        int money = 0;//记录赢的钱
        int tf = N-1,tl = 0,qf = N-1,ql = 0;
        for(int i=0; i>T[i];
        }
        for(int i=0; i>Q[i];
        }
        sort(T,T+N);
        sort(Q,Q+N);

        for(int i=0; iQ[qf]) {
                tf--;
                qf--;
                money += 200;
            } else if(T[tf]Q[ql]) {
                    //如果相等,比最慢的马,田忌的慢马快,就赛,最赚
                    tl++;
                    ql++;
                    money += 200;
                } else {
                //如果相等或比他小,就赛,不亏(相等的时候,自己也能必赢一局)
                    if(T[tl] < Q[qf]){
                        money -= 200;
                    }
                    qf--;
                    tl++;
                }
            }

        }
        cout<>N;
    }
}

你可能感兴趣的:(贪心算法)