算法设计与分析--贪心算法

版权声明:转载请标明本文来源,欢迎点赞评论一起学习ヾ(◍°∇°◍)ノ゙ https://blog.csdn.net/slyslyme/article/details/89048371

汽车加油问题

Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description

一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。并证明算法能产生一个最优解。
对于给定的n和k个加油站位置,计算最少加油次数。

Input

输入数据的第一行有2 个正整数n和k(n≤5000,k≤1000),表示汽车加满油后可行驶n公里,且旅途中有k个加油站。接下来的1 行中,有k+1 个整数,表示第k个加油站与第k-1 个加油站之间的距离。第0 个加油站表示出发地,汽车已加满油。第k+1 个加油站表示目的地。

Output

将计算出的最少加油次数输出。如果无法到达目的地,则输出“No Solution!”。

Sample Input

7 7
1 2 3 4 5 1 6 6

Sample Output

4

不晓得一开始为啥不理解题意·····反正就是贪心,在最大行驶千米限制下走的越远越好

#include <bits/stdc++.h>

using namespace std;

void jiayou(int n, int k, int a[])
{
    for(int i = 0; i <= k; i++)
    {
        if(n < a[i])  // 如果两个加油站之间的距离大于最大可行驶,直接ass
        {
            printf("No Solution!");
            return;
        }
    }
    int km = 0, cnt = 0;
    for(int i = 0; i <= k; i++)
    {
        km += a[i];  // 当前行驶的距离变化放在前边
        if(km > n) // 当前距离大于最大可行驶时,说明已经到了新加油的时候,所以次数加一
        {
            km = a[i];
            cnt++;
        }
    }
    printf("%d\n", cnt);
}

int main()
{
    int n, k, a[1010];
    cin>>n>>k;
    for(int i = 0; i <= k; i++)
    {
        cin>>a[i];
    }
    jiayou(n, k, a);
    return 0;
}
扫描二维码关注公众号,回复: 6051466 查看本文章

最优合并问题

Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description

给定k 个排好序的序列s1 , s2,……, sk , 用2 路合并算法将这k 个序列合并成一个序列。假设所采用的2 路合并算法合并2 个长度分别为m和n的序列需要m + n -1次比较。试设计一个算法确定合并这个序列的最优合并顺序,使所需的总比较次数最少。
为了进行比较,还需要确定合并这个序列的最差合并顺序,使所需的总比较次数最多。
对于给定的k个待合并序列,计算最多比较次数和最少比较次数合并方案。
 

Input

输入数据的第一行有1 个正整数k(k≤1000),表示有k个待合并序列。接下来的1 行中,有k个正整数,表示k个待合并序列的长度。

Output

输出两个整数,中间用空格隔开,表示计算出的最多比较次数和最少比较次数。

Sample Input

4
5 12 11 2

Sample Output

78 52

Hint

这个题的意思是给了四个序列进行合并,下边给出的四个数分别是四个序列的长度

根据贪心算法,最优时,应该先合并序列长度最小的, 最差时,就是应该先合并序列长度最大的

#include <bits/stdc++.h>

using namespace std;

int cmp(int a, int b) // 重写sort函数,从大到小排序
{
    return a > b;
}

int main()
{
    int k, a[1010], b[1010];
    cin>>k;
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    for(int i = 0; i < k; i++)
    {
        cin>>a[i];
        b[i] = a[i];
    }
    int num1 = 0, num2 = 0;
    sort(a, a + k); // 从小到大进行排序, 最优
    sort(b, b + k, cmp);  // 从大到小进行排序, 最差
    for(int i = 0; i < k - 1; i++)
    {
        a[i+1] = a[i] + a[i+1];
        num1 += a[i+1];
        sort(a+i+1, a+k);
        b[i+1] = b[i] + b[i+1];
        num2 += b[i+1];
        sort(b+i+1, b+k, cmp);  // 注意排序
    }
    num1 -= (k - 1); // 因为最后要减去(n-1)个1
    num2 -= (k - 1);
    cout<<num2<<" "<<num1<<endl;
    return 0;
}

装船问题

Problem Description

王小二毕业后从事船运规划工作,吉祥号货轮的最大载重量为M吨,有10货物可以装船。第i种货物有wi吨,总价值是pi。王小二的任务是从10货物中挑选若干上船,在满足货物总重量小于等于M的前提下,运走的货物的价重比最大。

Input

输入数据的第一行有一个正整数M(0 < M < 10000),表示所有货物最大载重量。在接下来的10行中,每行有若干个数(中间用空格分开),第i行表示的是第i种货物的货物的总价值pi ,重量wi(pi是wi的整数倍,0 < pi , wi < 1000)

Output

输出一个整数,表示可以得到的最大价值。

Sample Input

100
10 10
20 10
30 10
40 10
50 10
60 10
70 10
80 10
90 10
100 10

Sample Output

550
#include <bits/stdc++.h>

using namespace std;

// 不能拆分是动态规划 可拆分的是贪心


int main()
{
    int M, pi[1050], wi[1050], t;
    double val[1050];
    cin>>M;
    for(int i = 0; i < 10; i++)
    {
        cin>>pi[i]>>wi[i];
        val[i] = (pi[i] * 1.0) / wi[i];
    }
    for(int i = 0; i < 10; i++)  // 选择排序
    {
        for(int j = i + 1; j <= 9; j++)
        {
            if(val[i] < val[j])
            {
                t = val[i], val[i] = val[j], val[j] = t;
                t = pi[i], pi[i] = pi[j], pi[j] = t;
                t = wi[i], wi[i] = wi[j], wi[j] = t;
            }
        }
    }
    int maxVal = 0, h = 0;
    while(M >= 0 && h < 10)
    {
        if(wi[h] > M)  // 当最价值比的货物比最大载重还要大时,只能装最大价值比的货物,注意与最少硬币数(动态规划)的区别
        {
            maxVal += M / val[h];
            M = -1;
        }
        else
        {
            M -= wi[h];
            maxVal += pi[h];
        }
        h++;
    }
    printf("%d\n", maxVal);
    return 0;
}

区间覆盖问题

Time Limit: 1000 ms Memory Limit: 65536 KiB

Submit Statistic

Problem Description

设x1 , x2 ,…… , xn 是实直线上的n 个点。用固定长度的闭区间覆盖这n 个点,至少需要多少个这样的固定长度闭区间?
对于给定的实直线上的n个点和闭区间的长度k,设计解此问题的有效算法,计算覆盖点集的最少区间数,并证明算法的正确性。

Input

输入数据的第一行有2 个正整数n和k(n≤10000,k≤100),表示有n个点,且固定长度闭区间的长度为k。接下来的1 行中,有n个整数,表示n个点在实直线上的坐标(可能相同)。

Output

输出一个整数,表示计算出的最少区间数输出。

Sample Input

7 3
1 2 3 4 5 -2 6

Sample Output

3

Hint

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n, k, a[10010];
    cin>>n>>k;
    for(int i = 0; i < n; i++)
    {
        cin>>a[i];
    }
    sort(a, a + n);
    int temp = a[0], cnt = 1; // 初始cnt为1
    for(int i = 0; i < n; i++)
    {
        if(a[i] - temp > k)
        {
            cnt++;
            temp = a[i];  // 更新左端点
        }
    }
    cout<<cnt<<endl;
    return 0;
}

 

活动选择

Time Limit: 1000 ms Memory Limit: 65536 KiB

Submit Statistic

Problem Description

学校的大学生艺术中心周日将面向全校各个学院的学生社团开放,但活动中心同时只能供一个社团活动使用,并且每一个社团活动开始后都不能中断。现在各个社团都提交了他们使用该中心的活动计划(即活动的开始时刻和截止时刻)。请设计一个算法来找到一个最佳的分配序列,以能够在大学生艺术中心安排不冲突的尽可能多的社团活动。
比如有5个活动,开始与截止时刻分别为:



最佳安排序列为:1,4,5。

Input

第一行输入活动数目n(0<n<100);
以后输入n行,分别输入序号为1到n的活动使用中心的开始时刻a与截止时刻b(a,b为整数且0<=a,b<24,a,b输入以空格分隔)。

Output

输出最佳安排序列所包含的各个活动(按照活动被安排的次序,两个活动之间用逗号分隔)。

Sample Input

6
8 10
9 16
11 16
14 15
10 14
7 11

Sample Output

1,5,4
#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n, t;
    cin>>n;
    int s[105], e[105], num[105];
    for(int i = 0; i < n; i++)
    {
        cin>>s[i]>>e[i];
        num[i] = i + 1; // 开启一个数组记录活动的初始编号
    }
    for(int i = 0; i < n; i++)
    {
        for(int j = i + 1; j <= n - 1; j++)
        {
            if(e[i] > e[j])
            {
                t = e[i], e[i] = e[j], e[j] = t;
                t = s[i], s[i] = s[j], s[j] = t;
                t = num[i], num[i] = num[j], num[j] = t;
            }
        }
    }
    printf("%d", num[0]); // 该算法是只考虑最早结束的时间, 那么第一个活动在排序后一定是最早结束的 
    int temp = e[0];
    for(int j = 1; j < n; j++)
    {
        if(temp <= s[j])
        {
            printf(",%d", num[j]);
            temp = e[j];
        }
    }
    cout<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/slyslyme/article/details/89048371
今日推荐