贪心算法总结(C++)

贪心算法基本思想是由局部最优策略解决全局最优问题。贪心算法适用于解决的通常是那些解法结构可以分解为子问题最优结构的问题。

在学习贪心算法时,我主要在下面两道题时卡壳了。下面和大家分享一下这两道题。共勉!!!

1.区间选点问题

给定𝑛个闭区间,问最少需要确定多少个点,才能使每个闭区间中都至少存在一个点。

这道题我犯的错误主要是核心逻辑写错了,改了很久还未完全正确的代码如下:

#include <cstdio>

#include <algorithm>

using namespace std;

int n;

const int MAXNUM = 10005;

struct Area{

    int x;

    int y;

    bool havePoint;

    Area(){}

    Area(int _x, int _y){

        x = _x;

        y = _y;

    }

}a[MAXNUM];



bool cmp(Area a,Area b){

    //正确 if(a.x != b.x) return a.x > b.x;

    //正确 else return a.y > b.y;

    if(a.y != b.y) return a.y > b.y;  //错误

    else return a.x > b.x;  //错误

}

int count1 = 1;

int idx;

int pre = 0;

bool isComplete = false;

int main(){

    scanf("%d",&n);

    for(int i=0; i<n; i++){

        scanf("%d%d",&a[i].x,&a[i].y);

        a[i].havePoint = false;

    }

   

    sort(&a[0],&a[n],cmp);

   //暴力化的无用功(下)

    while(true){    

        for(idx = 1; idx < n; idx++){

            if(!a[idx].havePoint && a[idx].x <= a[pre].x && a[idx].y >= a[pre].x){

                a[idx].havePoint =true;

            }

        }

        isComplete = true;

        for(int idx1=1; idx1<n; idx1++){

            if(!a[idx1].havePoint){

                pre = idx1;

                a[idx1].havePoint = true;

                count1++;

                isComplete = false;

                break;

            }

        }

        if(isComplete) break;

    }

//暴力化的无用功(上)

    printf("%d",count1);

    return 0;

}

其中代码的核心逻辑是排序策略,是先由左端点值由大到小排序,再由右端点由小到大,(这里不知道为什么我试了一下再由右端点由大到小排序也能完美通过,我先把这个问题放在这里思考一下,可能也可以,也可能是数据不全面),而不是先由右端点值排序(虽然只是简单的两行代码写错,但写对了就是满分,写错了可能就是0分或碰巧对几组数据20分左右,差距挺大的)。我没有清楚地认识到这一点以至于去怀疑其他局部推导全局的过程逻辑出错了。方向错了当然导致最终失败。结果:答案错误(20%数据通过测试)

2.拼接最小数

题目:给定𝑛个可能含有前导0的数字串,将它们按任意顺序拼接,使生成的整数最小。

输入:

第一行为一个正整数𝑛(1≤𝑛≤104),表示数字串的个数。

第二行给出𝑛个数字串(1≤每个串的长度≤9),用空格隔开。

输出:

输出一个整数,表示能生成的最小整数(需要去掉前导0)。

下面是我写的答案错误(20%数据通过测试)的代码:

#include <cstdio>

#include <algorithm>

#include <vector>

using namespace std;

int n;

// const int MAXNUM = 10005;

vector<vector<char>> a;



char temp;

// char a[MAXNUM][9];

bool findFirst = false;

int main(){

    scanf("%d",&n);



    for(int i=0; i<n; i++){

        int j = 0;

        vector<char> tran;

        while(scanf("%c",&temp),temp != ' ' && temp != '\n'){

            tran.push_back(temp);

        }

        a.push_back(tran);

    }

    sort(a.begin(),a.end());

    for(int k=0; k<n; k++){

        for(int t=0; t<(int)a[k].size(); t++){

            if(a[k][t] != '0') findFirst = true;

            if(findFirst){

                printf("%c",a[k][t]);

            }

        }

    }

    if(!findFirst) printf("0");

    return 0;

}

下面是运行结果:

好吧,到现在我还没看出来我哪里错了,先放在这里,以后再回过头来研究。但是我知道题解的逻辑为什么是对的。在这里,我想提炼一下精华。题解代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 10000;
struct Interval {    // 区间结构体定义
    int l, r;
} interval[MAXN];    // 区间数组

bool cmp(Interval a, Interval b) {    // 区间的比较函数
    if (a.l != b.l) {                 // 如果左端点不同,那么按左端点从大到小
        return a.l > b.l;
    } else {                          // 否则,按右端点从小到大
        return a.r < b.r;
    }
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {         // 输入n个区间的左右端点
        scanf("%d%d", &interval[i].l, &interval[i].r);
    }
    sort(interval, interval + n, cmp);    // 将区间数组进行排序
    int num = 1, lastL = interval[0].l;   // 排序后的第一个区间的左端点总是被选中
    for (int i = 1; i < n; i++) {         // 遍历剩余的区间
        if (interval[i].r < lastL) {      // 如果和上一个选中的区间不相交(注意此处是闭区间,所以不能取到等号)
            lastL = interval[i].l;        // 那么选中当前区间的左端点
            num++;                        // 并令选中的点的数量加1
        }
    }
    printf("%d", num);                    // 输出选中的点数量
    return 0;
}

积累:

1.字符串处理工具: 数据结构:C++的string容器; 输入输出: C++的<iostream>头文件中的cin和cout; 排序(数字串也可以用字典序比数值大小):string直接比较大小,如string1 < string2; 拼接:string直接相加,如string1 + string2。

总之关于字符串的处理使用上面一套极为方便,比我先用定长二维数组然后发现不方便排序又改用vector容器结果结果还是不对要好多了。

(题解来源网站:晴问算法

最后总结一下:

1.答案错误,很少数据通过测试,很可能的原因是核心逻辑错误,一定要重新考虑一下整体逻辑问题。

2.字符串处理string,cin,cout工具处理很方便。

3.闭区间选点的排序顺序是先左端点从大到小再右端点从小到大。

保留的思考问题:

1.我的第二题代码错在哪里?是什么地方理解不到位?

2.先左端点从大到小再右端点从大到小是对的吗?

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
贪心算法是一种常见的算法思想,它在求解最优化问题时,每一步都选择当前看起来最优的解决方案,而不考虑全局最优解。对于五子棋这个游戏,贪心算法可以用来制定AI的策略。 在五子棋中,贪心算法可以通过评估当前局面的得分来选择下一步的落子位置。常见的评估方法是通过计算每个位置的连续棋子数来判断该位置的得分,然后选择得分最高的位置进行落子。 以下是一个简单的贪心算法五子棋的C++实现示例: ```cpp #include <iostream> #include <vector> using namespace std; const int SIZE = 15; // 棋盘大小 // 评估函数,计算某个位置的得分 int evaluate(vector<vector<int>>& board, int row, int col, int player) { int score = 0; int dx = {1, 0, 1, 1}; int dy[4] = {0, 1, 1, -1}; for (int i = 0; i < 4; i++) { int count = 0; int x = row, y = col; while (x >= 0 && x < SIZE && y >= 0 && y < SIZE && board[x][y] == player) { count++; x += dx[i]; y += dy[i]; } score += count; } return score; } // 贪心算法,选择得分最高的位置进行落子 void greedyAlgorithm(vector<vector<int>>& board, int player) { int maxScore = 0; int bestRow = -1, bestCol = -1; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (board[i][j] == 0) { int score = evaluate(board, i, j, player); if (score > maxScore) { maxScore = score; bestRow = i; bestCol = j; } } } } board[bestRow][bestCol] = player; } int main() { vector<vector<int>> board(SIZE, vector<int>(SIZE, 0)); // 初始化棋盘 // 玩家1先手落子 int player1 = 1; int row1, col1; cout << "玩家1,请输入落子位置(行 列):"; cin >> row1 >> col1; board[row1][col1] = player1; // AI玩家2贪心算法落子 int player2 = 2; greedyAlgorithm(board, player2); // 输出当前棋盘状态 for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { cout << board[i][j] << " "; } cout << endl; } return 0; } ``` 这段代码实现了一个简单的贪心算法五子棋的对战,玩家1先手输入落子位置,然后AI玩家2使用贪心算法选择最优位置进行落子,最后输出当前棋盘状态。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值