关于贪心算法的一些水题

书架

为了方便同学们查阅资料,程序设计兴趣小组的辅导老师打算将积攒了很多年的n本书放到上课教室的书架上去。

教室的书架是一层一层叠起来的,每一层最多可以放m本书。每一层的高度由放在这层中最高的那本书决定的,如果不放书,则认为这层的高度为0。为了使每个同学能方便地拿到想要的书,书架的总高度应尽可能低。请编程计算将这n本书放在书架上后书架的最小总高度,计算的过程中不考虑书的厚度与书架本身材料的厚度。

输入格式

输入共n+1行。

第1行2个整数n和m (1≤m≤n≤100000) 。

接下来n行,每行1个正整数,分别表示每本书的高度(每本书的高度不超过100)。

输出格式

输出共1行,表示将n本书放入书架后书架的最小总高度。

输入/输出例子1

输入:

3 2

20 10 30

输出:

40

样例解释

将高度是30和20的两本书放在一层,则这层的高度为30,将高度是10的那本书放在另外一层,则这层的高度为10,则书架的总高度为40,满足最小。

代码:
#include<bits/stdc++.h>
using namespace std;
bool cmp(int x,int y)
{
    return x>y;
}
int n,m,a[1000005],s;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i+=m)
        s+=a[i];
    cout<<s;
    return 0;
}

礼物

国庆马上要到了。小明喜欢的礼物有n种分别是:公仔、电子手表、漫画书等。

每种礼物有一件,每种礼物价钱都不一样。小明手头上有 m 元。

小明最多可以买多少件礼物?

输入格式

第一行,两个整数:n,m   1 <= n<=100,1<=m<= 100000。

第二行,n个空格分开的整数(每个整数<=1000),代表每种礼物的价钱。 

输出格式

一个整数,小明能买多少件礼物。

输入/输出例子1

输入:

3 100 

40 70 50 

输出:

2

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],ans,s;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
    {
        ans+=a[i];
        if(ans>m)break;
        else s++;
    }
    cout<<s;
    return 0;
}

数字圈

当我们写数字时会发现有些数字有封闭区域, 有的数字没有封闭区域。 数字 0 有一个封闭区域, 数字 1、 2、3 都没有封闭区域, 数字 4 有一个封闭区域, 数字 5 没有封闭区域, 数字 6 有一个封闭区域, 数字 7 没有

封闭区域, 数字 8 有两个封闭区域, 数字 9 有一个封闭区域。

现在你要构造一个最小的非负整数, 使得它的各位数字的封闭区域的数量加起来的总和恰好等于 K。

输入格式

一个整数 K。 1 <= K <= 2500。

输出格

满足题意的最小的非负整数。

输入/输出例子1

输入:

1

输出:

0

输入/输出例子2

输入:

2

输出:

8

输入/输出例子3

输入:

40

输出:

88888888888888888888

代码:
#include<bits/stdc++.h>
using namespace std;
int k;
int main(){
    cin>>k;
    if(k%2==0)
    {
        for(int i=0;i<k/2;i++)
            cout<<8;
        return 0;
    }
    if(k%2==1&&k!=1) 
    {
        cout<<4;
        for(int i=0;i<k/2;i++)
            cout<<8;
        return 0;
    }
    if(k==1)cout<<0;
    return 0;
}

危险的实验

小明最近在上化学课,他需要使用到 n 种化学物质来进行他的实验。在做实验的时候, 他需要将所有化学物质放在桌面上,按次序排成一条直线。 
然而每一种化学物质都是危险品,对于第 i个化学物质,如果有另外一个化学物质距离它的距离小于ai,那么就会发生爆炸。 
小明想知道如果要安全的完成他的实验,桌子最短可以多短。 

输入格式

第一行一个整数n,表示化学物质的个数。 
第二行有n个整数,第i个整数ai表示第i个化学物质必须与其他化学物质保持的距离。

输出格式

输出一行,包括一个整数,表示能够让小明安全完成实验的桌子最小长度。 
注意:物品要安原来的次序摆放。 

输入/输出例子1

输入:


3 1 2

输出:

5

数据范围 

20%的数据,1<=n<=20 ;
50%的数据,1<=n<=100000 ;
100%的数据,1<=n<=1000000,1<=ai<=100000。

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,a[1000005],s,t;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<n;i++)
    {
        t=max(a[i],a[i+1]);
        s+=t;
    }
    cout<<s;
    return 0;
}

最大步数

给出了两个非负整数 P 和 Q。您的任务是使得 P 和 Q 相等。在每一步中,您可以执行以下两项操作之一:

1、将任何质数加到 P 上。

2、从 Q 减去任何质数。

如果不可能使 P 和 Q 相等,则输出-1。否则,输出一个非负整数:可以执行的最大步数。

输入格式

一行,两个整数 P 和 Q。 0 <= P,Q <= 10^18

输出格式

一个整数。

输入/输出例子1

输入:

5 9

输出:

2

输入/输出例子2

输入:

5 10    

输出:

2

输入/输出例子3

输入:

5 6

输出:

-1

提示

数字0和1不是质数

代码:
#include<bits/stdc++.h>
using namespace std;
long long p,q;
int main()
{
    cin>>p>>q;
    if(p>q){cout<<-1;return 0;}
    if(p-q==0){cout<<0;return 0;}
    if(p-q==1){cout<<-1;return 0;}
    cout<<(q-p)/2;
    return 0;
}

渡河

总共有 X 人要坐船过河。

一个小船最多可以坐 4 人,一个小船固定收费 32 元。

一个大船最多可以坐 6 人,一个大船固定收费 36 元。

码头有无穷多小船和大船。

问如何坐船,才能使得总费用最小。

输入格式

一个整数 X。

60%的数据, 1 <= X <= 1000

80%的数据,1 <= X <= 1000000

100 的数据,1 <= X <= 2000000000

输出格式

一个整数,表示最小的总费用。

输入/输出例子1

输入:

4

输出:

32

输入/输出例子2

输入:

12

输出:

72

代码:
#include<bits/stdc++.h>
using namespace std;
long long x,s,l;
int main()
{
    cin>>x;
    if(x<=4)s=32;
    else
    {
        s+=(x/6)*36;
        l=x%6;
        if(l==5)s+=36;
        if(l==4||l==3)s+=32;
        if(l==2||l==1)s+=28;
    }
    cout<<s;
    return 0;
}

越野跑

为了能在下一次跑步比赛中有好的发挥,桐桐在一条山路上开始了她的训练 。桐桐希望能在每次训练中跑得尽可能远,不过她也知道农场中的一条规定:独自进山的时间不得超过M秒(1 <= M <= 10,000,000)。

整条山路被桐桐划分成T个长度相同的小段(1 <= T <= 100,000),用S_i表示第i个小段的路况。S_i为U,F,D这3个字母之一,它们分别表示第i个小段是上坡、平地,或是下坡。

桐桐要花U秒(1 <= U <= 100)才能跑完一段上坡路,跑完一段平地的耗时是F秒(1 <= F <= 100),跑完一段下坡路要花D秒(1 <= D <= 100)。注意,沿山路原路返回的时候,原本是上坡路的路段变成了下坡路,原本是下坡路的路段变成了上坡路。

桐桐想知道,在能按时返回农场的前提下,她最多能在这条山路上跑多远。

输入格式

第1行: 5个用空格隔开的整数:M,T,U,F,D。

第2..T+1行: 第i+1行为1个字母S_i,描述了第i段山路的路况。

输出格式

输出1个整数,为桐桐在按时回到农场的前提下,最多能跑到多远。

输入/输出例子1

输入:

13 5 3 2 1

ufudf

输出:

3

样例解释

桐桐跑步的最大耗时为13秒(这么短...),她跑步的山路一共被划成5段。桐桐跑完一段上坡路的耗时为3秒,平地为2秒,下坡路为1秒。山路各段的走向如下图所示:

 

20211203002014_15009.png

桐桐跑完山路的前3段,然后返回,总耗时为3 + 2 + 3 + 1 + 2 + 1 = 12秒,只比她能在外面呆的时限少1秒。如果她跑得更远,就无法按时回到农场

代码:
#include<bits/stdc++.h>
using namespace std;
int m,t,u,f,d,ans,o,i;
string s;
int main(){
    cin>>m>>t>>u>>f>>d>>s;
    while(1)
    {
        if(s[i+1]=='u'||s[i+1]=='d')ans=(u+d);
        else ans=f*2;
        if(o+ans>m||i==s.size())break;
        if(s[i]=='u'||s[i]=='d')o+=(u+d);
        else o+=f*2;
        i++;
    }
    cout<<i;
    return 0;
}

逃生

迷宫被分成N行M列的格子。从上往下看,行的编号是1至N。从左往右看,列的编号是1至M。你现在位于第1行第1列格子,迷宫的出口在第N行第M列的格子。每进入一个格子都要消耗能量。迷宫格子的能量有点奇特,同一行格子消耗的能量是相等的,第1行的每一个格子消耗的能量都是E[1],第2行的每一个格子消耗的能量都是E[2],....第N行的每一个格子消耗的能量都是E[N]。现在你要从左上角格子走到右下角格子,每一步可以从当前格子走到相邻的上、下、左、右四个格子之一,你的目标是消耗最小的总能量。注意:左上角格子和右下角格子消耗的能量也要算。

输入格式

第一行,M和N。

接下来有N个数,第i个是E[i]。

输出格式

一个整数。

输入/输出例子1

输入:

5  6

3  2  5  4  2  8

输出:

32

输入/输出例子2

输入:

3 3

1 2 1    

输出:

6

输入/输出例子3

输入:

4 4

3 2 4 2

输出:

17

数据范围

1<=N<=50,1<=M<=1000000000。注意:M表示列,N表示行。

1<=E[i]<=1000。

代码:
#include<bits/stdc++.h>
using namespace std;
long long x,n,sum,m,minn=10000;
int main(){
    cin>>m>>n;
    for(int i=0;i<n;i++)
    {
        cin>>x;
        sum+=x;
        minn=min(minn,x);
    }
    cout<<sum+minn*(m-1);
    return 0;
}

二零二零

给出一个字符串S,其中满足S的每一个字符都是数字字符,你要删除S的连续一段字符(也可以删除0个字符),使得剩下的字符依次连接起来的字符串是“2020”,可以做到吗?如果可以做到输出“YES”,否则输出“NO”。

输入格式

第一行,一个整数G,表示有G组测试测试。1<=G<=10。

每组测试格式如下:

第一行,一个整数n,表示字符串S的长度。1<=n<=200。

第二行,字符串S。

输出格式

共G行,每行一个字符串,“YES”或“NO”,双引号不用输出。

输入/输出例子1

输入:

5

8

20192020

8

22019020

4

2020

5

20002

6

729040

输出:

YES

YES

YES

NO

NO

代码:
#include<bits/stdc++.h>
using namespace std;
int g,n;
string s;
bool jjj(string s)
{
    int len=s.size();
    if(s[0]=='2'&&s[len-3]=='0'&&s[len-2]=='2'&&s[len-1]=='0')return true;
    if(s[0]=='2'&&s[1]=='0'&&s[len-2]=='2'&&s[len-1]=='0')return true;
    if(s[0]=='2'&&s[1]=='0'&&s[2]=='2'&&s[len-1]=='0')return true;
    if(s[len-4]=='2'&&s[len-3]=='0'&&s[len-2]=='2'&&s[len-1]=='0')return true;
    if(s[0]=='2'&&s[1]=='0'&&s[2]=='2'&&s[3]=='0')return true;
    return false;
}
int main()
{
    cin>>g;
    while(g--)
    {
        cin>>n;
        cin>>s;
        if(jjj(s)==true)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    
    return 0;
}

学生分组

有N组学生,给出初始时每组中的学生个数,再给出每组学生人数的上界R和下界L(L<=R),每次你可以在某组中选出一个学生把他安排到另外一组中,问最少要多少次才可以使N组学生的人数都在[L,R]中。

输入格式

第一行一个整数N,表示学生组数;1<=N<=100
第二行N个整数K,表示每组的学生个数;1<=K<=100
第三行两个整数 L,R,表示下界和上界。

输出格式

一个数,表示最少的交换次数,如果不能满足题目条件输出-1

输入/输出例子1

输入:

4

10 20 30 40

18 28

输出:

14

代码:
#include<bits/stdc++.h>
using namespace std;
int n,l,r;
int a[100009];
int s,h;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        s+=a[i];
    }
    cin>>l>>r;
    int s1,s2;
    if(s<l*n||s>r*n)
    {
        cout<<"-1";
        return 0;
    }
    else
    {
        for(int i=0;i<n;i++)
        {
            if(a[i]<l)s1+=l-a[i];
            if(a[i]>r)s2+=a[i]-r;
        }
    }
    cout<<max(s1,s2)<<endl;
    return 0;
}

回文数列

czm非常喜欢回文数列。回文数列是指一个包含N个整数的数列A,分别为A[1],A[2],……,A[n],对于第i(1<=i<=N)个数A[i],都有A[i]=A[N-i+1]。但是回文数字非常难得到。

现在czm想到了一个办法,他可以将数列中,任意两个相邻的数字合并,用它们的和来代替,合并完成的值还可以和其他值不断合并,直到只剩下一个数。要知道一个数肯定是回文数列。

当然,czm希望他的回文数列尽可能长,因此,请你帮助czm计算一下,对于一个长度为N的数列,经过最少多少次合并,可以构成一个回文数列。

输入格式

第一行一个整数N(1<=N<=500000),表示数列中整数的个数。

第二行包含N个正整数,中间用空格分开,表示数列中的数字。

输出格式

输出一个最小合并次数,使得数列变成回文数列。

输入/输出例子1

输入:

3

1 2 3

输出:

1

输入/输出例子2

输入:

5
1 2 4 6 1

输出:

1

输入/输出例子3

输入:

4
1 4 3 2

输出:

2

代码:
#include<bits/stdc++.h>
using namespace std;
long long a[1000005],n,ans;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1,j=n;i<j;)
    {
        if(a[i]==a[j])i++,j--;
        else if(a[i]>a[j])a[j-1]+=a[j],j--,ans++;
        else if(a[i]<a[j])a[i+1]+=a[i],i++,ans++;
    }
    cout<<ans;
    return 0;
}

均分纸牌

有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若干张纸牌,然后移动。
移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。
例如 N=4,4 堆纸牌数分别为:  ① 9 ② 8 ③ 17 ④ 6   移动3次可达到目的: 从 ③ 取 4 张牌放到 ④ (9 8 13 10) -> 从 ③ 取 3 张牌放到 ②(9 11 10 10)-> 从 ② 取 1 张牌放到①(10 10 10 10)。 

输入格式

第一行N。第二行A1 A2 … An (每堆纸牌初始数) 

输出格式

所有堆均达到相等时的最少移动次数。 (1 <= N <= 100,l<= Ai <=10000 ) 

输入/输出例子1

输入:

4

9 8 17 6 

输出:

3

代码:
#include<bits/stdc++.h>
using namespace std;
int num[105],n,ave,tot,ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>num[i];
        tot+=num[i];
    }
    ave=tot/n;
    for(int i=1;i<=n;i++)
        num[i]-=ave;
    for(int i=1;i<n;i++)
    {
        if(num[i]==0) continue;
        num[i+1]+=num[i];
        ans++;
    }
    cout<<ans;
    return 0;
}

叠罗汉

农场的N头奶牛喜欢玩叠罗汉游戏,就是几头奶牛1头奶牛接着1头奶牛的站成一柱子形状。不过奶牛的力量不一样,用数值Ci表示第i头奶牛它的上面最多可以站多少头奶牛,问这些奶牛最少可以站成几个柱子形状。

输入格式

第一行1个整数N,表示有多少头奶牛。1<=N<=1000。

第二行N个正整数Ci,表示这些奶牛的力量。0<=Ci<=1000。

输出格式

一个整数,表示最少成几个“罗汉”。

输入/输出例子1

输入:

5

0 2 1 2 2

输出:

2

样例解释

可以第1、第3、第2头奶牛从上向下叠罗汉;

第4、第5头奶牛叠罗汉。

代码:
#include<bits/stdc++.h>
using namespace std;
int n,f,ans,c[1005],k,d;
int main(){
	cin>>n;
	for (int i=0;i<n;i++)
	{
		cin>>f;
		c[f]++;
	}
	while(k<n)
	{
		d=0;
		ans++;
		for(int i=0;i<1000;)
		{
			if(c[i]!=0&&i>=d)
			{
				c[i]--;
				k++;
				d++;
			}
            else i++;
		}
	}
	cout<<ans;
    
    return 0;
}

菜鸟整理的一些题,大佬不喜勿喷......

一 。课程设计题目:漫步迷宫 二 。问题描述: 用mn的m*n个正方格表示一个迷宫,其中划有斜线的方格表示不可通,未划有斜线的方格表示可以通。请编写寻找从入口到出口的一条最短路径的程序。 三 。基本要求: 1。迷宫的规格(即数与数),状态设置(即各方格能否通的状态),以及入口和出口的位置,均应由输入随机确定。 2。求得的最短路径,应该以从入口到出口的路径上的各个方格的坐标的线性序输出。当无通路时,应该报告无路径的信息。 3。尽量采用结构化程序设计方法,要求对各个模块的功能及参数作必要的说明。 四 。实现提示: 1。迷宫可以采用matrix类型的二维数组A表示。A.rownum与A.colnum分别表示迷宫的实际的数与数。而A.maze[i][j]表示迷宫中第i第j的一个方格,用A.maze[i][j]=0表示该方格可以通,用A.maze[i][j]=1表示该方格不可以通。 2。由于要寻找从入口到出口的一条最短路径,最好将迷宫看作是一个图结构。则问题转化为寻找从对应于入口顶点到对应于出口顶点的一条最短路径的问题。该问题可以采用从入口顶点出发,进广度优先搜索遍历,直到遇到出口顶点或者遍历完毕也没有遇到出口顶点为止。这二种情况分别对应于最短路径探索成功与查无通路的事实。 3。基于上述分析,涉及到数据结构的转换,即将二维数组表示的迷宫A转换为以adjlist 类型的邻接表表示的图结构G。在图结构中,将迷宫中的每个方格看作是一个顶点。不可通的方格都是孤立顶点;相邻的可通的方格所对应的顶点之间看作是有边相连。因此迷宫 可以看作是由m*n个顶点及无向边构成的一个非连通的无向图。尽管图是不连通的,但不影响本问题的求解,而且本问题有解的条件是:入口顶点与出口顶点在同一个连通分量中。 图结构G中,G.adj[k]表示编号为k的顶点的邻接情况的单链表的头指针;G.vexnum表示图G中的实际顶点数,而且具有如下关系:G.vexnum=A.rownum*A.colnum 4。为了避免迷宫数据的重复输入,我们期望A能够自动地转换为G。因此应该设计一个转换算法create_adjlist(A,G)。而图结构中顶点是要编号的,我们约定以为序,顺序给迷宫A中的方格所对应的顶点编号。这样迷宫中方格的坐标(即row和col)与图G中所对应的顶点的编号(即verno)之间具有如下关系: verno=(row-1)* n + col row=(verno-1)/ n + 1 col=(verno-1)% n + 1 5。在广度优先搜索遍历求解最短路径过程中,应该设置一个队queue作为辅助数据结构;路径采用一个整数数组pred来表示。这二个数据结构的存储结构类型均为list类型,其说明定义如下:typedef int list[MAXVER]; 队queue应该设置front和rear分别指示首与尾,queue[k]表示第k个入的顶点编号。采用pred记录路径,pred[i]表示顶点i在广度优先搜索遍历过程中的前趋顶点的编号,它表明是经过边(pred[i],i)达到顶点i的。这样,当路径探索成功时,我们可以从出口顶点倒推出从入口到出口的一条路径来。当然要涉及到从顶点编号向方格坐标的反转换,这个公式在上面已经给出了。
当涉及到背包问题时,贪心算法是一种常用的解决方法。在C语言中,可以使用贪心算法来解决背包问题。下面是一个简单的C语言贪心算法背包问题的代码示例: ```c #include <stdio.h> // 定义物品结构体 typedef struct { int weight; // 物品重量 int value; // 物品价值 } Item; // 贪心算法背包问题函数 void knapsack(Item items[], int n, int capacity) { // 计算物品的性价比(价值除以重量) float ratios[n]; for (int i = 0; i < n; i++) { ratios[i] = (float) items[i].value / items[i].weight; } // 按照性价比排序物品 for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (ratios[j] < ratios[j + 1]) { // 交换物品的位置 float tempRatio = ratios[j]; ratios[j] = ratios[j + 1]; ratios[j + 1] = tempRatio; Item tempItem = items[j]; items[j] = items[j + 1]; items[j + 1] = tempItem; } } } // 装入背包 int currentWeight = 0; float totalValue = 0; for (int i = 0; i < n; i++) { if (currentWeight + items[i].weight <= capacity) { // 将物品放入背包 currentWeight += items[i].weight; totalValue += items[i].value; } else { // 物品只能部分放入背包 int remainingWeight = capacity - currentWeight; totalValue += ratios[i] * remainingWeight; break; } } // 输出结果 printf("背包中物品的总价值为: %.2f\n", totalValue); } int main() { // 创建物品数组 Item items[] = { {10, 60}, {20, 100}, {30, 120} }; int n = sizeof(items) / sizeof(items[0]); // 物品数量 int capacity = 50; // 背包容量 // 调用贪心算法背包问题函数 knapsack(items, n, capacity); return ; } ``` 这段代码实现了一个简单的贪算法背包问题。它首先计算每个物品性价比,然后按照性价比对物品进排序。接下来,它从性价比最高的物品开始,依次将物品放入背包,直到背包装满或者所有物品都放入背包。最后,输出背包中物品的总价值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值