排队接水
时间限制: 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.0tot/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);
 }