第八章 - 贪心法

UVA120 煎饼 Stacks of Flapjacks

思路:

要求通过翻转 1~刀插入位置的所有数,使煎饼的半径做到从小到大排,那么思路就很清晰了:先找到最大的数,翻转把它扔到最后,再找到第二大的数,也想办法翻转,扔到倒数第二个;

这里会出现一个问题:

就是这个我们要找的当前最大数是否在第1位,如果是,则直接翻转最后一个煎饼,把这个半径最大的煎饼扔到后面去;如果不是呢?就把它翻转到第一位,再扔到后面去;

简单来说,找到起始位置 i 和结束位置 p,然后从两边开始交换。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main() {
    string line;
    while (getline(cin, line)) {
        vector<int> a, b;
        stringstream ss(line);  // 使用字符串流解析数字
        int p;
        while (ss >> p) {a.push_back(p);b.push_back(p);}
        sort(b.begin(), b.end());//升序排序作为模版
        
        p = b.size();//从最后一个开始处理  /* cout << a[p-1] << endl; */
        while(p > 0){
            bool cg = true;
            for (size_t t = 0; t < a.size(); t++){if(a[t] != b[t]) cg = false;} 
            if(cg){cout << '0' << endl;break;}
            
            int i = 0;
            for (size_t t = 0; t < p; t++){
                if(a[t] == b[p-1]) i = t;
            }    //将第 p 个数的数组下标给 i 
            if(i != p-1){
                if(i != 0){//第 p 个数不在最上面,翻转到最上面
                    reverse(a.begin(),a.begin() + i + 1);
                    cout << b.size() - i << ' ';
                }
                
                //将第 p 个数翻转到最下层(比p直径大的上一层)
                reverse(a.begin(),a.begin() + p);
                cout << b.size() - p + 1 << ' ';
            }
            p--;
        }
    }
    return 0;
}

UVA11134 传说中的车 Fabled Rooks

首先,我们发现其实x轴与y轴是互不相关的,可以独立求解。于是我们把x轴与y轴分开求解。于是问题就变成了:在[1,n]的区间中,有一些区间,在每一个区间中选一个点,使最终恰好覆盖[1,n]中的这n个点。

开始时,我想的是以l作为第一关键字,r作为第二关键字进行排序。然后从左往右扫。然而这样显然是不成立的,[1,3],[1,3],[2,2]这组数据就会被卡掉。

在用贪心法解决问题时,我们可以考虑:如果要选择几种状态,一种决策的"后路"覆盖了所有其他决策的"后路",那我们不应当选择这种决策。(可能我语文不怎么好,那就用这道题解释一下吧。)

试想一下,如果我们要求从前往后做出抉择,且有两段区间都可以选择,那我们应该选择哪一段?显然是r值小的哪一段。应为对于后面的点,r值小的可以覆盖的点r值大的也可以覆盖,而r值大的可覆盖的点r值小的可能无法覆盖。这样,我们可以认为r值大的"后路"覆盖了r值小的的所有后路,于是我们应该选r值小的。于是我们就不难想到方法:以r(后路)作为关键字排序(r相同的可以随意排),然后对于每一个序列,从l到r扫描。如果是该点没有被选择过,那就选择该点。

问题分解:将二维棋盘问题分解为两个独立的一维问题

贪心策略 :按右端点从小到大排序,然后每个区间选择最小的可用位置

正确性:右端点小的区间选择余地小,应该优先安排

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    while (cin >> n && n) {
        struct Node { int l, r, id; };
        vector<Node> rows(n), cols(n);
        
        // 读取
        for (int i = 0; i < n; i++) {
            int xl, yl, xr, yr;
            cin >> xl >> yl >> xr >> yr;
            rows[i] = {xl, xr, i};
            cols[i] = {yl, yr, i};
        }
        
        // 按右端点排序
        auto cmp = [](const Node& a, const Node& b) {
            return a.r == b.r ? a.l < b.l : a.r < b.r;
        };
        sort(rows.begin(), rows.end(), cmp);
        sort(cols.begin(), cols.end(), cmp);
        
        vector<int> ans_x(n), ans_y(n);
        vector<bool> used_x(n + 1, false), used_y(n + 1, false);
        bool ok = true;
        
        // 处理x坐标
        for (auto& node : rows) {
            int pos = node.l;
            while (pos <= node.r && used_x[pos]) pos++;
            if (pos > node.r) { ok = false; break; }
            used_x[pos] = true;
            ans_x[node.id] = pos;
        }
        
        // 处理y坐标
        if (ok) {
            for (auto& node : cols) {
                int pos = node.l;
                while (pos <= node.r && used_y[pos]) pos++;
                if (pos > node.r) { ok = false; break; }
                used_y[pos] = true;
                ans_y[node.id] = pos;
            }
        }
        
        // 输出
        if (ok) {
            for (int i = 0; i < n; i++) 
                cout << ans_x[i] << " " << ans_y[i] << endl;
        } else {
            cout << "IMPOSSIBLE" << endl;
        }
    }
    return 0;
}
相关推荐
VT.馒头2 小时前
【力扣】2625. 扁平化嵌套数组
前端·javascript·算法·leetcode·职场和发展·typescript
wanghu20242 小时前
AT_abc443_C~E题题解
c语言·算法
梵刹古音2 小时前
【C语言】 浮点型(实型)变量
c语言·开发语言·嵌入式
历程里程碑2 小时前
Linux 17 程序地址空间
linux·运维·服务器·开发语言·数据结构·笔记·排序算法
u0109272712 小时前
模板元编程调试方法
开发语言·c++·算法
??(lxy)2 小时前
java高性能无锁队列——MpscLinkedQueue
java·开发语言
2401_838472512 小时前
C++图形编程(OpenGL)
开发语言·c++·算法
-dzk-2 小时前
【代码随想录】LC 203.移除链表元素
c语言·数据结构·c++·算法·链表
进击的小头3 小时前
陷波器实现(针对性滤除特定频率噪声)
c语言·python·算法