日志:贪心

排队接水

时间限制: 1 Sec 内存限制: 128 MB
题目描述
有n 个人在一个水龙头前排队接水,假如每个人接水的时间为ti ,请编程找出这n 个人
排队的一种顺序,使得n 个人的平均等待时间最小。
输入
第一行为n(1<=n<=5000)。第二行分别表示第1 个人到第n 个人每人的接水时间t1,
t2…,tn,每个数据之间有一个空格。(0<=ti<=10000)
输出
共两行,第一行为一种排队顺序,即1 到n 的一种排列,且保证小序号靠前(如:“2 3”
与“3 2”,在平均等待时间一样时,输出“2 3”;第二行为这种排列方案下的平均等待时
间(输出结果精确到小数点后两位,在小数点后三进行四舍五入)。
样例输入
10
56 12 1 99 1000 234 33 55 99 812
样例输出
3 2 7 8 1 4 9 6 10 5
291.90
解析:
这题比较简单,要使得后面等待的时间少,那么尽量让接水时间短的人排在前面,于是
我们可以使用二级排序,优先让接水时间短的人排在前面,如果接水时间一样,就按读入的
顺序小的排在前面,这样就能做到最优方案了,至于最终的时间,就模拟一下统计总时间,
然后除以人数。(需要注意的是,第一个人不用等待,但第一个人接水的时间就是第二个人
等待时间,最后一个人的接水时间没意义,因为没人等待了)

#include// 不难
#include
using namespace std;
struct ren{
int time,id;
}(p[5100]);
bool cmp(ren x,ren y){
if(x.time!=y.time)return x.time<y.time;
return x.id<y.id;
}
int main(){
int i,tot=0,n;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&p[i].time);
p[i].id=i;
}
sort(p+1,p+n+1,cmp);
for(i=1;i<=n;i++){
tot += (n-i)p[i].time;
printf("%d “,p[i].id);
}
printf(”%.2f",1.0
tot/n);
return 0;
}

最大整数

时间限制: 1 Sec 内存限制: 128 MB
题目描述
设有n 个正整数(n<=20),将它们连接成一排,组成一个最大的多位数。
例如:n=3 时,3 个整数13,312,343 连接成的最大整数为:34331213
又如:n=4 时,4 个整数7,13,4,246 连接成的最大整数为:7424613
输入
第1 行,n;
第2 行,n 个数。
输出
连接成的多位数。
样例输入
3 13 312 343
样例输出
34331213
解析:
此题很容易想到使用贪心法,在考试时有很多同学把整数按从大到小的顺序连接起来,
测试题目的例子也都符合,但最后测试的结果却不全对。按这种标准,我们很容易找到反例:
12,121 应该组成12121 而非12112,那么是不是相互包含的时候就从小到大呢?也不一
定,如12,123 就是12312 而非12123,这种情况就有很多种了。是不是此题不能用贪
心法呢?
其实此题可以用贪心法来求解,只是刚才的标准不对。我们发现更最基本的排序一样,
哪个数字在前,哪个数字在后,比较的是两种方案的大小比较。假设已经有最优方案产生前
面的数字t,当前要比较先接a,还是先接b,我们可以比较t+a+b 和t+b+a(这里的“+”
是连接符号),如果t+a+b>=t+b+a,那么先接a,反之先接b。但其实只要比较a+b 和
b+a 就行了,因为t 是公共部分,于是基本的贪心策略就出来了:
先把整数转换成字符串,然后比较a+b 和b+a,如果a+b>=b+a,就把a 排在b 的前
面,反之则把a 排在b 的后面。

#include//也不太难
#include
#include
using namespace std;
char s[1002],s1[1002],change[1002];
void charu(){
int a=atof(s);
int b=atof(s1);
int l=strlen(s);
int l1=strlen(s1);
if(apow(10,l1)+b>=bpow(10,l)+a) strcat(s,s1);
else{
strcpy(change,s);
strcpy(s,s1);
strcat(s,change);
}
}
int main(){
int i,n;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%s",s1);
if(i==1){
strcpy(s,s1);
continue;
}
charu();
}
printf("%s",s);
}

纪念品分组【NOIP2007】

时间限制: 1 Sec 内存限制: 128 MB
题目描述
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获
得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两
件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时
间内发完所有纪念品,乐乐希望分组的数目最少。
你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
输入
含n+2 行:
第1 行包括一个整数w,为每组纪念品价格之和的上限;
第2 行为一个整数n,表示购来的纪念品的总件数;
第3-n+2 行每行包含一个正整数Pi(5<=Pi<=w),表示所对应纪念品的价格。
输出
仅一行,包含一个整数,即最少的分组数目。
样例输入
100
9 90
20
20
30
50
60
70
80
90
样例输出
6
提示
50%的数据满足: 1<=n<=15
100%的数据满足: 1<=n<=30000,80<=W<=200
解析:
题目要求每个组最多分两个纪念品,如果是小的数字,那么它可能可以跟很多其他数字
组合,比如样例:90 20 20 30 50 60 70 80 90,比如20 可以有很多的组合选择;
但大的数字可以组合的机会比较少,比如90 没的选择,80 只能跟20 组合才不会超过100,
因此我们发现可以从较大数字优先着手:
首先排序,当前剩余数字中最大的数字如果能跟最小的数字组合,就让它们分为一组,
否则最大数字单独一组,并弹掉最大的数字,重复上述操作,直到数字取光,那么构成的组
数即为答案。

#include //也也不太难
#include
#include
#include
using namespace std;
int main(){
int i,n,w,tot,a[30002],place=1;
scanf("%d%d",&w,&n);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
tot=n;
for(i=n;i>place;i–){
if(a[i]+a[place]<=w){
tot–;
place++;
}
}
printf("%d",tot);
}

零件分组

时间限制: 1 Sec 内存限制: 128 MB
题目描述
某工厂生产一批棍装零件,每个零件都有一定的长度(li)和重量(wi).现在为了加工需
要,要将它们分成若干组,使每一组的零件都能排成一个长度和重量都不下降(若i<j,则
li<=lj,wi<=wj)的序列。请问至少要分成几组。
输入
第一行为一个整数n(n<=1000),表示零件的个数。第二行有n 对正整数,每对正整数表示
这些零件的长度和重量,长度和重量均不超过10000。
输出
仅一行,即最少分成的组数。
样例输入
58
4
3 8
2 3
9 7
3 5
样例输出
2
提示
二级排序
解析:
首先我们二级排序,那么问题就只需要比较没有排序的另一边数据,比如1 3 2 6 4
7 5,刚开始1 就分成组1,元素为{1},当3 来的时候,可以放到组1,就不额外增加组
了{1, 3}, 2 来的时候有分歧了,可以是{1,2} {3},也可以是{1,3} {2},那么我
们发现两种情况其实效果一样,因为每个分组在乎的是最后一个数字,那么我们任意选择
{1,3}{2}的方案,因为这样就不用调整3 了。再来6 的时候,我们发现,6 接到3 后面
比较好,使得两组末尾的数字变为{6}{2},比{6}{3}要好。4 来的时候,接到2 后面,7
来的时候接6 后面,5 来的时候接4 后面,于是方案就为{1,3,6,7}{2,4,5}
这个时候贪心策略就自然出来了,也就是每个数字开始,往后取数字,取比它大的接在
后面,比它小的先忽略,一直取到数列最后,构成一个分组。接下来重新开始选择数字,构
成第二个分组,直到数列中的元素取完。那么最终有多少组就是答案。

#include//这道题的本质就是记录最小值更新的次数,我觉得我编的比题解要更好一些
#include
#include
#include
using namespace std;
int main(){
int n,l[1002],w[1002],i,min,judge=1,tot=1;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&l[i],&w[i]);
}
sort(l+1,l+1+n);
for(i=2;i<=n;i++){
if(judge){
if(w[i]<w[i-1]){
tot++;
judge=0;
min=w[i];
}//一开始min相当于w[i-1]
}
else{
if(w[i]<min) tot++;
}
}
printf("%d",tot);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值