【题解】贪心二题

晚上刷了两道贪心题,难度不大,我的码力也有进步

LuoGu1233木棍加工
题目描述

一堆木头棍子共有n根,每根棍子的长度和宽度都是已知的。棍子可以被一台机器一个接一个地加工。机器处理一根棍子之前需要准备时间。准备时间是这样定义的:

第一根棍子的准备时间为1分钟;

如果刚处理完长度为L,宽度为W的棍子,那么如果下一个棍子长度为Li,宽度为Wi,并且满足L>=Li,W>=Wi,这个棍子就不需要准备时间,否则需要1分钟的准备时间;

计算处理完n根棍子所需要的最短准备时间。比如,你有5根棍子,长度和宽度分别为(4, 9),(5, 2),(2, 1),(3, 5),(1, 4),最短准备时间为2(按(4, 9)、(3, 5)、(1, 4)、(5, 2)、(2, 1)的次序进行加工)。

输入输出格式

输入格式:
第一行是一个整数n(n<=5000),第2行是2n个整数,分别是L1,W1,L2,w2,…,Ln,Wn。L和W的值均不超过10000,相邻两数之间用空格分开。

输出格式:
仅一行,一个整数,所需要的最短准备时间。

输入样例
5
4 9 5 2 2 1 3 5 1 4
输出样例
2

【题解】
这倒算是贪心的入门题了吧,类似导弹拦截的思想,先以L为第一关键字,W为第二关键字进行稳定的排序,保证了单调不上升。
因为可以自己排顺序,所以就分成几组,每组里是不需要花时间的,两组之间的切换花1min时间(就跟导弹拦截一样)然后新来一根棍子时,若能加入已有的组,那么在其中选W最小的加入;否则自己新开一组

Code:

#include 
#define res register int
#define ll long long
#define maxn 5010
#define inf 2147483647
using namespace std;
struct Node{
    int l,r;
}a[maxn];
int f[maxn],n,ans;

inline int read(){
    int s = 0,w = 1;
    char c = getchar();
    while (c < '0' || c > '9'){
        if (c == '-') w = -1; c = getchar();
    }
    while (c >= '0' && c <= '9') s = s * 10 + c - '0',c = getchar();
    return s * w;
}
inline bool cmp(Node x,Node y){
    return (x.l > y.l || x.l == y.l && x.r > y.r);
}
int main(){
    n = read();
    for (res i = 1; i <= n; ++ i) a[i].l = read(),a[i].r = read();
    sort(a + 1,a + n + 1, cmp);
    for (res i = 1; i <= n; ++ i){
        int s = 0, k = inf;
        for (res j = 1; j <= ans; ++ j)
         if (f[j] >= a[i].r && f[j] < k) s = j, k = a[i].r;
        if (s == 0) f[++ans] = a[i].r; else f[s] = a[i].r;
    }
    printf("%d\n",ans);
    return 0;
}

LuoGu2123:皇后游戏
题目背景

还记得 NOIP 2012 提高组 Day1 的国王游戏吗?时光飞逝,光阴荏苒,两年

过去了。国王游戏早已过时,如今已被皇后游戏取代,请你来解决类似于国王游

戏的另一个问题。

题目描述

皇后有 n 位大臣,每位大臣的左右手上面分别写上了一个正整数。恰逢国庆节来临,皇后决定为 n 位大臣颁发奖金,其中第 i 位大臣所获得的奖金数目为第i-1 位大臣所获得奖金数目与前 i 位大臣左手上的数的和的较大值再加上第 i 位大臣右手上的数。
形式化地讲:我们设第 i 位大臣左手上的正整数为 ai,右手上的正整数为 bi,则第 i 位大臣获得的奖金数目为 ci可以表达为:
图片
当然,吝啬的皇后并不希望太多的奖金被发给大臣,所以她想请你来重新安排一下队伍的顺序,使得获得奖金最多的大臣,所获奖金数目尽可能的少。
注意:重新安排队伍并不意味着一定要打乱顺序,我们允许不改变任何一位大臣的位置。

输入输出格式

输入格式:
第一行包含一个正整数 T,表示测试数据的组数。
接下来 T 个部分,每个部分的第一行包含一个正整数 n,表示大臣的数目。
每个部分接下来 n 行中,每行两个正整数,分别为 ai和 bi,含义如上文所述。

输出格式:
共 T 行,每行包含一个整数,表示获得奖金最多的大臣所获得的奖金数目。

输入样例#1:
1
3
4 1
2 2
1 2
输出样例#1:
8
输入样例#2:
2
5
85 100
95 99
76 87
60 97
79 85
12
9 68
18 45
52 61
39 83
63 67
45 99
52 54
82 100
23 54
99 94
63 100
52 68
输出样例#2:
528
902

【题解】
类似于Noip2012国王游戏,贪心的方法也与之类似,不过这两道题有不同的难点:国王游戏难在高精,本题难在排序方法的制定
我自己搞出一个正确但不最优的cmp,这位大佬的题解写的很好,给我很大的启发
我改善了cmp后,只有12分,原因是我printf里%lld打成了%d

Code:

#include 
#define res register int
#define ll long long
#define maxn 20010
#define inf 2147483647
using namespace std;
struct Node{
    ll x,y,d;
}a[maxn];
ll n,c[maxn];

inline int read(){
    int s = 0,w = 1;
    char c = getchar();
    while (c < '0' || c > '9'){
        if (c == '-') w = -1; c = getchar();
    }
    while (c >= '0' && c <= '9') s = s * 10 + c - '0',c = getchar();
    return s * w;
}
inline bool cmp(Node x,Node y){
    if (x.d != y.d) return x.d < y.d;
    if (x.d <= 0) return x.x < y.x;
    return x.y > y.y;
}
int main(){
    int m = read();
    while (m --){
        n = read();
        for (res i = 1; i <= n; ++ i){
            a[i].x = read(),a[i].y = read();
            if (a[i].x > a[i].y) a[i].d = 1;
            else if (a[i].x < a[i].y) a[i].d = -1;
            else a[i].d = 0;
        }
        sort(a + 1, a + 1 + n,cmp);
        ll sum = 0;
        for (res i = 1; i <= n; ++ i){
            sum += a[i].x; c[i] = max(c[i - 1], sum) + a[i].y;
        }
        printf("%lld\n",c[n]);
    }
    return 0;
}

你可能感兴趣的:(题解,贪心,LuoGu)