高效算法设计举例

摘自算法《竞赛入门经典训练指南》

例题 年龄排序(Age Sort,UVa 11462)

给定若干居民的年龄(都是1~100之间的整数),把它们按照从小到大的顺序输出。

【输入】

输入包含多组测试用例。每组数据的第一行为整数n(0<n<=2 000 000),即居民总数;下一行包含n个不小于1、不大于100的整数,即各居民的年龄。输入结束标志为n=0。

输入文件约有25mb,而内存限制只有2mb。

【输出】

对于每组数据,按照从小到大的顺序输出各居民的年龄,相邻年龄用单个空格隔开。

【分析】

由于数据太大,内存限制吃紧(甚至都不能把它们全读入内存),因此无法使用快速排序方法。但整数范围很小,可以用计数排序方法。下面是程序代码。

#include <cstdio>
#include <cstring>
int main(){
	int n,x,c[101];
	while(scanf("%d",&n)==1 && n){
		memset(c,0,sizeof(c));
		for(int i=0;i<n;i++){
			scanf("%d",&x);
			c[x]++;
		}
		int first=1;
		for(int i=1;i<=100;i++){
			for(int j=0;j<c[i];++j){
				if(!first)printf(" ");
				first=0;
				printf("%d",i );
			}
		}
		printf("\n");
	}
}

  

如果还要精益求精,可以优化输入输出,进一步降低运行时间。程序如下。

#include <cstdio>
#include <cstring>
#include <cctype>

inline int readint(){
	char c=getchar();
	while(!isdigit(c))c=getchar();

	int x=0;
	while(isdigit(c)){
		x=x*10+c-‘0‘;
		c=getchar();
	}
	return x;//Warning: x > 0;
}

int buf[10];
inline void writeint(int i){
	int p=0;
	if(i==0)p++;
	else while(i){
		buf[p++]=i%10;
		i/=10;
	}
	for(int j=p-1;j>=0;j--)putchar(‘0‘+buf[j]);//逆序输出
}

int main(){
	int n,x,c[101];
	while(n=readint()){
		memset(c,0,sizeof c);
		for(int i=0;i<n;++i)c[readint()]++;

		int first=1;
		for(int i=0;i<=100;++i){
			for(int j=0;j<c[i];++j){
				if(!first)putchar(‘ ‘);
				first=0;
				writeint(i);
			}
		}
		putchar(‘\n‘);
	}
	return 0;
}

  

上述优化使得程序运行时间缩短了约2/3。一般情况下,当输入输出数据量很大时,应尽量用scanf和printf函数;如果时间效率还不够高,应逐字符输入输出,就像上面的readint和writeint函数。不管怎样,在确信I/O时间成为整个程序性能瓶颈之前,不要盲目优化。测试方法也很简单:输入之后不执行主算法,直接输出一个任意的结果,看运行时间是否过长。

时间: 2024-12-29 11:22:09

高效算法设计举例的相关文章

第八章 高效算法设计

分治法求最大连续和 注意范围是[x,y) #include<bits/stdc++.h> using namespace std; int maxsum(int *A,int x,int y){ if(y-x==1) return A[x]; int m=x+(y-x)/2; int maxs = max(maxsum(A,x,m),maxsum(A,m,y)); int v,L,R; v=0; L=A[m-1]; for(int i=m-1;i>=x;i--) L=max(L,v+=A

UVa 1210 (高效算法设计) Sum of Consecutive Prime Numbers

题意: 给出n,求把n写成若干个连续素数之和的方案数. 分析: 这道题非常类似大白书P48的例21,上面详细讲了如何从一个O(n3)的算法优化到O(n2)再到O(nlogn),最后到O(n)的神一般的优化. 首先筛出10000以内的素数,放到一个数组中,然后求出素数的前缀和B.这样第i个素数一直累加到第j个素数,就可表示为Bj - Bi-1 枚举连续子序列的右端点j,我们要找到Bj - Bi-1 = n,也就是找到Bi-1 = Bj - n. 因为Bj是递增的,所以Bi-1也是递增的,所以我们就

集训第四周(高效算法设计)O题 (构造题)

A permutation on the integers from 1 to n is, simply put, a particular rearrangement of these integers. Your task is to generate a given permutation from the initial arrangement 1, 2, 3, . . . , n using only two simple operations. •  Operation 1: You

集训第四周(高效算法设计)A题 Ultra-QuickSort

原题poj 2299:http://poj.org/problem?id=2299 题意,给你一个数组,去统计它们的逆序数,由于题目中说道数组最长可达五十万,那么O(n^2)的排序算法就不要再想了,接下来的选择是快排,归并,看你喜欢了 这里列出归并的解法: #include"iostream" using namespace std; const int maxn=500000+10; int T[maxn]; int a[maxn]; long long sum; void merg

集训第四周(高效算法设计)N题 (二分查找优化题)

原题:poj3061 题意:给你一个数s,再给出一个数组,要求你从中选出m个连续的数,m越小越好,且这m个数之和不小于s 这是一个二分查找优化题,那么区间是什么呢?当然是从1到数组长度了.比如数组长度为10,你先找5,去枚举每一个区间为5的连续的数,发现存在这样的数,那么就可以继续往左找,反之则往右找,直到左右区间重合,即为正确答案,(有可能是右区间小于左区间,所以每次都应该求区间中点值) #include"iostream" #include"set" #incl

集训第四周(高效算法设计)M题 (扫描法)

原题:UVA11078 题意:给你一个数组,设a[],求一个m=a[i]-a[j],m越大越好,而且i必须小于j 怎么求?排序?要求i小于j呢.枚举?只能说超时无上限.所以遍历一遍数组,设第一个被减数为a[0],之后遇到比a[0]大的数就更新它,再拿这个被减数去减数组中的每一个元素,同时也要不断地更新这个m值. #include"iostream" #include"set" #include"cstring" #include"cst

集训第四周(高效算法设计)L题 (背包贪心)

Description John Doe is a famous DJ and, therefore, has the problem of optimizing the placement of songs on his tapes. For a given tape and for each song on that tape John knows the length of the song and the frequency of playing that song. His probl

(高效算法设计)之高维问题 废料堆 Garbage heap Uva 10755

#include <iostream> #include <algorithm> #define FOR(i,s,p) for(int i=(s);i<=(p);i++) using namespace std; void expand(char i, bool b[]){ b[0] = i & 1; i >>= 1; b[1] = i & 1; i >>= 1; b[2] = i & 1; } // 这里使用了二项式中的思想,

集训第四周(高效算法设计)P题 (构造题)

Description There are N<tex2html_verbatim_mark> marbles, which are labeled 1, 2,..., N<tex2html_verbatim_mark> . The N<tex2html_verbatim_mark> marbles are put in a circular track in an arbitrary order. In the top part of the track there