贪心专题训练二

1:会场安排问题

作者 陈晓梅
单位 广东外语外贸大学
题目来源:王晓东《算法设计与分析》

假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的
贪心算法进行安排。(这个问题实际上是著名的图着色问题。若将每一个活动作为图的一个
顶点,不相容活动间用边相连。使相邻顶点着有不同颜色的最小着色数,相应于要找的最小
会场数。)

输入格式:
第一行有 1 个正整数k,表示有 k个待安排的活动。
接下来的 k行中,每行有 2个正整数,分别表示 k个待安排的活动开始时间和结束时间。时间
以 0 点开始的分钟计。

输出格式:
输出最少会场数。

输入样例:

5
1 23
12 28
25 35
27 80
36 50 

输出样例:
在这里给出相应的输出。例如:

3

代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB

解析:我们只需要用贪心算法对每一次遍历求最优解,最多进行n次就一定可以遍历晚所以时间,但是这是按结束时间排序会出现错误,必须得用开始时间排序,原因未知

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010;

int vis[N];

struct node
{
    
    
    int x, y;
    bool operator < (const node &a)
    {
    
    
        return x < a.x;
    }
}f[N];

int main()
{
    
    
    int n;
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> f[i].x >> f[i].y;
    
    sort(f, f + n);
    
    int cnt = 0;
    for (int i = 0; i < n; i ++ )
    {
    
    
        if(!vis[f[i].y])
        {
    
    
            cnt ++;
            vis[f[i].y] = 1;
            int end = f[i].y;
            for(int j = i + 1; j < n; j ++ )
            {
    
    
                if(end <= f[j].x && !vis[f[j].y])
                {
    
    
                    end = f[j].y;
                    vis[f[j].y] = 1;
                }
            }
        }
    }
    cout << cnt;
    
    return 0;
}

2:h0145. 会议安排

作者 黄正鹏
单位 贵州工程应用技术学院

学校的礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办。小刘的工作就是安排学校礼堂的活动,每个时间最多安排一个活动。现在小刘有一些活动计划的时间表,他想尽可能的安排更多的活动,请问他该如何安排。

输入格式:
第一行是一个整型数m(m<100)表示共有m组测试数据。
每组测试数据的第一行是一个整数n(1<n<10000)表示该测试数据共有n个活动。
随后的n行,每行有两个正整数Bi,Ei(0<=Bi,Ei<10000),分别表示第i个活动的起始与结束时间(Bi<=Ei)

输出格式:
对于每一组输入,输出最多能够安排的活动数量。
每组的输出占一行

输入样例:
在这里给出一组输入。例如:

2
2
1 10
10 11
3
1 10
9 11
11 20

输出样例:
在这里给出相应的输出。例如:

2
2

代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010;

struct node
{
    
    
    int x, y;
    bool operator < (const node &a)
    {
    
    
        return y < a.y;
    }
}f[N];

int main()
{
    
    
    int T;
    cin >> T;
    while (T -- )
    {
    
    
        int n;
        cin >> n;
        for (int i = 0; i < n; i ++ ) cin >> f[i].x >> f[i].y;

        sort(f,f + n);

        int end = f[0].y;
        int cnt = 1;
        for (int i = 0; i < n - 1; i ++ )
        {
    
    
            if(end <= f[i + 1].x)
            {
    
    
                end = f[i + 1].y;
                cnt ++;
            }
        }
        cout << cnt << endl;
    }
    return 0;
}

3:最少失约

作者 usx程序设计类课程组
单位 绍兴文理学院

某天,诺诺有许多活动需要参加。但由于活动太多,诺诺无法参加全部活动。请帮诺诺安排,以便尽可能多地参加活动,减少失约的次数。假设:在某一活动结束的瞬间就可以立即参加另一个活动。

输入格式:
首先输入一个整数T,表示测试数据的组数,然后是T组测试数据。每组测试数据首先输入一个正整数n,代表当天需要参加的活动总数,接着输入n行,每行包含两个整数i和j(0≤i<j<24),分别代表一个活动的起止时间。

输出格式:
对于每组测试,在一行上输出最少的失约总数。

输入样例:

1
5
1 4
3 5
3 8
5 9
12 14

输出样例:

2

代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB

解析:我们只需要用贪心策略求出最优解,然后使用总活动数减去最优解就可以得到最少的失约策略

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

struct node
{
    
    
    int x, y;
    bool operator < (const node &a)
    {
    
    
        return y < a.y;
    }
}f[N];

int main()
{
    
    
    int T;
    cin >> T;
    while (T -- )
    {
    
    
        int n;
        cin >> n;
        for (int i = 0; i < n; i ++ ) cin >> f[i].x >> f[i].y;

        sort(f,f + n);

        int end = f[0].y;
        int cnt = 1;
        for (int i = 0; i < n - 1; i ++ )
        {
    
    
            if(end <= f[i + 1].x)
            {
    
    
                end = f[i + 1].y;
                cnt ++;
            }
        }
        cout << n - cnt << endl;
    }
    return 0;
}

4:活动选择问题

作者 李廷元
单位 中国民用航空飞行学院

假定一个有n个活动(activity)的集合S={a1 ,a2 ,…,an},这些活动使用同一个资源(例如同一个阶梯教室),而这个资源在某个时刻只能供一个活动使用。每个活动ai都有一个开始时间si和一个结束时间fi,其中0<=si <fi<=32767。如果被选中,任务ai发生在半开时间区间[si,fi )期间。如果两个活动ai 和aj 满足[si ,fi)和[sj,fj)不重叠,则称它们是兼容的。也就说,若si >=fj或sj>=f i,则ai 和aj是兼容的。在活动选择问题中,我们希望选出一个最大兼容活动集。

输入格式:
第一行一个整数n(n≤1000);

接下来的n行,每行两个整数,第一个si ,第二个是fi (0<=si <fi<=32767)。

输出格式:
输出最多能安排的活动个数。

输入样例:

11
3 5
1 4
12 14
8 12
0 6
8 11
6 10
5 7
3 8
5 9
2 13

输出样例:

4

样例解释:
安排的4个活动为1 4, 5 7, 8 11和12 14。

代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

struct node
{
    
    
    int x, y;
    bool operator < (const node &a)
    {
    
    
        return y < a.y;
    }
}f[N];

int main()
{
    
    
    int n;
    while (cin >> n)
    {
    
    
        for (int i = 0; i < n; i ++ ) cin >> f[i].x >> f[i].y;

        sort(f,f + n);

        int end = f[0].y;
        int cnt = 1;
        for (int i = 0; i < n - 1; i ++ )
        {
    
    
            if(end <= f[i + 1].x)
            {
    
    
                end = f[i + 1].y;
                cnt ++;
            }
        }
        cout << cnt << endl;
    }
    return 0;
}

5:删数问题

作者 任唯
单位 河北农业大学

有一个长度为n(n <= 240)的正整数,从中取出k(k < n)个数,使剩余的数保持原来的次序不变,求这个正整数经过删数之后最小是多少。

输入格式:
n和k

输出格式:
一个数字,表示这个正整数经过删数之后的最小值。

输入样例:

178543 4

输出样例:

13

代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB

解析:根据贪心策略,只要每一次选最优解,最终结果一定是最优解,这题刚开想到的策略是每次删掉最大的一个数,剩下的序列一定是最优解,通过反证法得出如果一个数中间有一串零的情况会出错,例如:30008 1最优解应该是8,所以后面思考力一下发现只要每次删除的数比后面一个数大就一定可以得到最优解

#include <iostream>

using namespace std;

int vis[250];

int main()
{
    
    
    string s;
    int n;
    cin >> s >> n;
    
    for (int i = 0; i < n; i ++ )
    {
    
    
        for (int j = 0; j < s.size(); j ++ )
            if(s[j] > s[j + 1] || j == s.size() - 1)
            {
    
    
                s.erase(s.begin() + j);
                break;
            }
    }
    while (s[0] == '0') s.erase(s.begin()); //  删除前导零
    
    cout << s;
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_52331221/article/details/127811420