写在最前:
高中学信息技术或者搞过信奥的可能对这方面已经有些基础,但很可惜本人并没有这方面的基础。这半个月时间也是初次涉猎。这里放的只是目前遇到的一部分,在后面还会继续补题。题目均来自TZOJ。
大致分为两个内容:来自公开赛的题目和和作业里的部分题目以及类似题。每一部分的内容布置是按照难度循序渐进的,刚开始几道不是很复杂的题目我都用c来写,后面几道用c++。因为过程一复杂再用c的话,代码就会显得有些重复累赘了。
11.14集训队简单贪心专题(部分题目)
1001 心疼giegie
描述
哥哥,你骑着小,小电动车,载~着我,你女朋友知道了,不会揍我吧!
好(浩)可(克)怕你女朋友~
不像我,我只会心疼giegie~
这个视频大家都看过吧!
现在,这个giegie要给这个女的买n件礼物。
giegie有x元,每买一件礼物,这个giegie的危险程度就是这个的金额的50%,输出giegie最多可以给那个“绿茶”几件礼物(在危险值不大于500的情况下)。
输入
第一行两个正整数:n(0<=n<=100)表示看中了n件商品,x(0<=x<=10000)表示giegie有几块钱。
下面n行,每行一个实数,表示每件礼物的价格,不超过500。
输出
输出giegie最多可以买到的礼物数量。
样例输入
2 1546
271
154
样例输出
2
签到题。从小到大排序之后,从小的开始买才可以达到目的。
#include<stdio.h>
#define maxn 1001
void sort(int a[],int n)
{
int i,j,t;
for(i=1;i<n;i++)
{
for(j=0;j<n-1;j++)
{
if(a[j]>a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
}
int main()
{
int a[maxn],n,x,i,j,k,s=0,sum=0,warn=0;
scanf("%d%d",&n,&x);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,n);
for(i=0;i<n;i++)
{
sum+=a[i];
warn+=a[i]*0.5;
if(sum<=x&&warn<=500)
s+=1;
}
printf("%d",s);
return 0;
}
1002 整数区间
描述
请编程完成以下任务:
1.从文件中读取闭区间的个数及它们的描述;
2.找到一个含元素个数最少的集合,使得对于每一个区间,都至少有一个整数属于该集合,输出该集合的元素个数。
输入
首行包括区间的数目n,1≤n≤10000,接下来的n行,每行包括两个整数a,b,被一空格隔开,0≤a≤b≤10000,它们是某一个区间的开始值和结束值。
输出
输出集合元素的个数, 对于每一个区间都至少有一个整数属于该集合, 且集合所包含元素数目最少。
样例输入
4
3 6
2 4
0 2
4 7
样例输出
2
先审题。我画了一张图,题目的意思大致如下:
解析:
对于区间问题,区间的起点和终点是有内在联系的,而且在众多组数据中,仅仅是这两个数据之间存在联系,因此需要用到结构体。
在这里,sum表示的是题目要求的数组中元素的个数。在逐个输入每一个区间范围之后,对每个区间的右端点进行从小到大的排序。排序完成后,每次选取其中一个右端点将右端点和其他的左端点进行比较,如果说比较结果是大于,说明两个区间有元素重合,若小于则必不可能有元素重合。那么遇到重合的情况则sum=1即可,如果遇到不重合的情况则sum需要多一个元素来搭建一个“桥”。比如我上面的这张图,对于【0,2】这个区间,需要4这个元素,来和其他三个区间建立起联系,4就是一座桥。但是你不需要知道这座“桥”具体是什么数,因此直接让sum++。
因为右端点是从小到大顺序排的,既然出现了不重合的情况,并且“桥”已经搭起来了,如果说题目并没有说明“要求数组元素个数最小”,你依然可以用这个右端点继续比下去。但既然题目规定了,那就得让第二小的右端点进行下一轮比较,可以节约搭“桥”的数量。
#include<stdio.h>
#define maxn 10001
struct node{
int a;
int b;
}z[maxn],t;
int main(){
int n;
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++){
scanf("%d%d",&z[i].a,&z[i].b);
}
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
if(z[i].b>z[j].b){
t=z[i];
z[i]=z[j];
z[j]=t;
}
}
}
int temp=z[1].b;
int sum=1;
for(i=2;i<=n;i++){
if(temp<z[i].a){
sum++;
temp=z[i].b;
}
}
printf("%d",sum);
return 0;
}
1003 小船过河
描述
N个人要过河,但只有一条小船,每次只能坐2人,每个人有不同的划船速度,而两个人一起过河时小船速度由最慢的人的速度决定。请设计一个过河方案,使得所有人均过河,且所用总时间最少。
输入
第一行为正整数N(N<=1000),表示人数,第二行为N个正整数,表示每个人的速度(这里是时间值,值越小速度越快),不超过100。
输出
输出花费最少的总时间。
样例输入
4
1 2 5 10
样例输出
17
一开始做的时候没有想到要分类讨论,吃了几次亏之后才发现,运人有两种方法(在这里,速度最快的假设为1,速度第二快的假设为2,速度最慢的设为99,速度第二慢的设为98,以此类推):
方法一:
让1做摆渡人,来回都有他。每次1载一名速度大的,直到运完。
方法二:
第一趟先把1、2运过去,然后再让1把船开回来,让98、99乘船过去,再让2把船开回来,这是一个循环。接下来让99和98在对岸不动,再把1、2运到对岸,1把船开回来,97、96乘船过去,2把船开回来。。。。就这样循环下去,最后注意奇偶的讨论就可以了。
可以自己试一下,两种方法解出来的时间是不一样的。但是在人数小于等于三时,第一种方法可以求出最优解,大于三时,第二种方法可以求出最优解。
#include<stdio.h>
int time[1010];
void sort(int a[],int n)
{
int i,j,t;
for(i=1;i<n;i++)
{
for(j=0;j<n-1;j++)
{
if(a[j]>a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
}
int main()
{
int n,i,b,N;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&time[i]);
}
sort(time,n);
int sum=0;
while(n>3)
{
if(2*time[1]+time[0]>2*time[0]+time[n-2])
sum+=2*time[0]+time[n-2]+time[n-1];
else
sum+=2*time[1]+time[0]+time[n-1];
n-=2;
}
if(n==3)
sum+=time[1]+time[0]+time[2];
if(n==2)
sum+=time[1];
if(n==1) sum += time[0];
printf("%d",sum);
return 0;
}
1004 taozi的小难题
描述
从前有一个抠门的国王taozi,一天他的领土受到了其它国家的侵略,于是taozi决定组建一个骑士团击退敌人。当然招募骑士也是需要花费金币的,这里就以骑士的攻击力来给金币,抠门的taozi看到了这么多骑士前来,很头痛,于是taozi找到了聪明的你,让你去帮他解决这个问题。
输入
输入多组数据,对于每组数据,第一行输入一个n,m,分别代表n个敌人和m个骑士,接下来n个数代表敌人的攻击力a,然后m个数代表雇佣骑士的攻击力b,多组数据以n=0,m=0结束。
数据规定
1≤n,m≤10000
1≤a,b≤100
输出
对于每组数据,输出国王最少需要花费多少金币雇佣骑士才能杀死所有敌人,如果不行输出-1。
样例输入
2 3
5 4
7 8 4
2 1
5 5
10
0 0
样例输出
11
-1
提示
第一组数据,taozi选择第3号骑士打败2号敌人,选择第1号骑士打败1号敌人,总共花费11元。
第二组数据,taozi无论怎么选都打不过敌人。
题目规定了数组的范围时100,那就直接开两个100的数组就好,直接用下标进行比较。下标比较总比数组元素比较来的方便。这里的sum是金币的数值,a代表敌人的攻击力,b代表骑士的攻击力,那么把a放在外循环,把b放在内循环。让b数组从小到大遍历,这样可以做到和a最接近。这里的f是用来判断能不能找到,注意break只能中断离他最近的那个循环。
#include<stdio.h>
#include<string.h>
#define maxn 1001
int main()
{
int i,j,k,n,m,x;
int a[maxn],b[maxn];
while(scanf("%d%d",&n,&m),n||m)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(i=0;i<n;i++)
{
scanf("%d",&x);
a[x]++;
}
for(i=0;i<m;i++)
{
scanf("%d",&x);
b[x]++;
}
int sum=0,f=1;
for(i=1;i<=100;i++)
{
for(j=1;j<=a[i];j++)
{
f=0;
for(k=i;k<=100;k++)
{
if(b[k]>0)
{
b[k]--;
sum+=k;
f=1;
break;
}
}
if(f==0)break;
}
if(f==0)break;
}
if(f==0)printf("-1\n");
else printf("%d\n",sum);
}
return 0;
}
未完待续
欢迎评论区,私信交流!