演算法初步之排序
這一小節的內容都是排序,排序所能涉及到的內容很多。在這些題目中,冒泡,選擇排序偶爾會用到。因為涉及到的資料量並不大,因此不會超時。多數情況下,呼叫sort函式可以解決大部分需要排序的東西。sort內部採用類似快速排序的的機制運作,很少會超時。還有就是在操作字串的時候,很多細節還是要注意,否則很容易遇到莫名其妙的執行錯誤。這一節的題目比較簡單,接下來是這一節的九道題目。
問題A:
題目描述
對輸入的n個數進行排序並輸出。
輸入
輸入的第一行包括一個整數n(1<=n<=100)。 接下來的一行包括n個整數。
輸出
可能有多組測試資料,對於每組資料,將排序後的n個整數輸出,每個數後面都有一個空格。
每組測試資料的結果佔一行。
樣例輸入
5 5 4 3 1 2
樣例輸出
1 2 3 4 5
#include<cstdio>
int main(){
int n;
while(scanf("%d",&n)!=-1){
//只有不到100個數,先試一下選擇排序
//依次從剩下的元素中找到最小(大)的元素
//設計為先,很重要。根據思路去敲程式碼,而不是瞎搞,浪費時間
//流程很重要,remember
int a[103];
int i;
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(i=0;i<n;i++)
for(int j=i;j<n;j++){
if(a[j]<=a[i]){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
for(i=0;i<n;i++)
printf("%d ",a[i]);
printf("\n");
}
return 0;
}
問題B:
題目描述
輸入一系列整數,將其中最大的數挑出,並將剩下的數進行排序。
輸入
輸入第一行包括1個整數N,1<=N<=1000,代表輸入資料的個數。
接下來的一行有N個整數。
輸出
可能有多組測試資料,對於每組資料,
第一行輸出一個整數,代表N個整數中的最大值,並將此值從陣列中去除,將剩下的數進行排序。
第二行將排序的結果輸出。
樣例輸入
5
5 3 2 4 1
樣例輸出
5
1 2 3 4
提示
如果陣列中只有一個數,當第一行將其輸出後,第二行請輸出"-1"。
#include<cstdio>
#include<cstring>
const int M=1005;
int main(){
//處理只有一個數字的情況:第一行數字,第二行-1
//處理有N個數字的情況 :第一行最大數,第二行其餘數字的升序
//1~1000
//資料範圍小就是好做
int n,a[M];
while(scanf("%d",&n)!=-1){
if(n==1){
scanf("%d",&a[0]);
printf("%d\n",a[0]);
printf("-1\n");
}
else{
int i;
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(i=0;i<n;i++)
for(int j=i;j<n;j++){
if(a[i]>=a[j]){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
printf("%d\n",a[n-1]);
for(i=0;i<n-1;i++){
printf("%d ",a[i]);
}
printf("\n");
}
memset(a,0,sizeof(a));
}
return 0;
}
問題C:
題目描述
Excel可以對一組紀錄按任意指定列排序。現請你編寫程式實現類似功能。
對每個測試用例,首先輸出1行“Case i:”,其中 i 是測試用例的編號(從1開始)。隨後在 N 行中輸出按要求排序後的結果,即:當 C=1 時,按學號遞增排序;當 C=2時,按姓名的非遞減字典序排序;當 C=3 時,按成績的非遞減排序。當若干學生具有相同姓名或者相同成績時,則按他們的學號遞增排序。
輸入
測試輸入包含若干測試用例。每個測試用例的第1行包含兩個整數 N (N<=100000) 和 C,其中 N 是紀錄的條數,C 是指定排序的列號。以下有N行,每行包含一條學生紀錄。每條學生紀錄由學號(6位數字,同組測試中沒有重複的學號)、姓名(不超過8位且不包含空格的字串)、成績(閉區間[0, 100]內的整數)組成,每個專案間用1個空格隔開。當讀到 N=0 時,全部輸入結束,相應的結果不要輸出。
輸出
對每個測試用例,首先輸出1行“Case i:”,其中 i 是測試用例的編號(從1開始)。隨後在 N 行中輸出按要求排序後的結果,即:當 C=1 時,按學號遞增排序;當 C=2時,按姓名的非遞減字典序排序;當 C=3 時,按成績的非遞減排序。當若干學生具有相同姓名或者相同成績時,則按他們的學號遞增排序。
樣例輸入
4 1 000001 Zhao 75 000004 Qian 88 000003 Li 64 000002 Sun 90 4 2 000005 Zhao 95 000011 Zhao 75 000007 Qian 68 000006 Sun 85 4 3 000002 Qian 88 000015 Li 95 000012 Zhao 70 000009 Sun 95 0 3
樣例輸出
Case 1: 000001 Zhao 75 000002 Sun 90 000003 Li 64 000004 Qian 88 Case 2: 000007 Qian 68 000006 Sun 85 000005 Zhao 95 000011 Zhao 75 Case 3: 000012 Zhao 70 000002 Qian 88 000009 Sun 95 000015 Li 95
#include<cstdio>
#include<algorithm>
#include<cstring>
const int M=100009;
typedef struct {
char num[10];
char name[10];
int grade;
}students;
students s[M];
bool cmp(students a,students b){
return strcmp(a.num,b.num)<0; //remeber this
} //具體實現以後再看
bool cmp1(students a,students b){
if(!strcmp(a.name,b.name))
return strcmp(a.num,b.num)<0;
else
return strcmp(a.name,b.name)<0;
}
bool cmp2(students a,students b){
if(a.grade==b.grade)
return strcmp(a.num,b.num)<0;
else
return a.grade<b.grade ;
}
int main(){
//選擇,快速,希爾,桶,奇偶,冒泡,歸併
/*排序有要求
1:學號遞增(衝突時優先)
2:姓名非遞減
3:分數非遞減 */
/*資料輸入,輸出格式
N是記錄條數,C是排序選擇
依次6位學號,8位連續姓名,【0,100】的分數
N位0時程式結束*/
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int i,n,c,t=0;
while(scanf("%d%d",&n,&c)!=-1&&n!=0){
for(i=0;i<n;i++){
scanf("%s%s%d",s[i].num,s[i].name,&s[i].grade);
}
switch(c){
case 1:std::sort(s,s+n,cmp);
break;
case 2:std::sort(s,s+n,cmp1);
break;
case 3:std::sort(s,s+n,cmp2);
break;
}
t++;
printf("Case %d:\n",t);
for(i=0;i<n;i++)
printf("%s %s %d\n",s[i].num,s[i].name,s[i].grade);
memset(s,0,sizeof(s));
}
return 0;
}
問題D:
題目描述
輸入一個字串,長度小於等於200,然後將輸出按字元順序升序排序後的字串。
輸入
測試資料有多組,輸入字串。
輸出
對於每組輸入,輸出處理後的結果。
樣例輸入
tianqin
樣例輸出
aiinnqt
提示
注意輸入的字串中可能有空格。
#include<cstdio>
#include<algorithm>
#include<cstring>
bool cmp(char a,char b){
return a<b;
}
int main(){
//每次都要分析題目後寫設計思路
//輸入長度小於200的字串,對其排序後輸出
//排序選擇:字元陣列內部排序(考慮空格情況) ,如果不給提示,第一次應該想不到
//不會,字串都是些什麼玩意兒
//試一下: 假設全是小寫字母,我理解的是輸出不含空格
//這道題簡直實在侮辱 ,什麼玩意兒
char a[205],b[205];
while(gets(a)!=NULL){
int i,j,l=strlen(a);
for(i=0,j=0;i<l;i++){
if(a[i])
b[j++]=a[i];
}
int ll=strlen(b);
std::sort(b,b+ll,cmp);
printf("%s\n",b);
memset(b,0,sizeof(b));
}
return 0;
}
問題E:
題目描述
請寫一個程式,對於一個m行m列的(1<m<10)的方陣,求其每一行,每一列及主對角線元素之和,最後按照從大到小的順序依次輸出。
輸入
共一組資料,輸入的第一行為一個正整數,表示m,接下來的m行,每行m個整數表示方陣元素。
輸出
從大到小排列的一行整數,每個整數後跟一個空格,最後換行。
樣例輸入
4 15 8 -2 6 31 24 18 71 -3 -9 27 13 17 21 38 69
樣例輸出
159 145 144 135 81 60 44 32 28 27
#include<cstdio>
#include<algorithm>
#include<cstring>
bool cmp(int a,int b){
return a>b;
}
int main(){
//分析:輸入m行m列的矩陣(整數,1<m<10)
//計算行,列,主隊角元素之和
//對計算出的數字排序,需要控制個數m+m+1+1,然後輸出
//測試只對一半(在下一次計算時,清空陣列) (什麼叫測試資料範圍)
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int m,a[10][10],sum[22];
while(scanf("%d",&m)!=-1 ){ //忘了寫-1而導致輸出超限
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
int i,j ;
for(i=0;i<m;i++)
for(j=0;j<m;j++){
scanf("%d",&a[i][j]);
sum[i]+=a[i][j]; //m行數字的和
}
for(j=0;j<m;j++)
for(i=0;i<m;i++){
sum[m+j]+=a[i][j]; //m列數字的和
}
for(i=0;i<m;i++){ //對角線元素之和
sum[m+m]+=a[i][i];
sum[m+m+1]+=a[i][m-1-i];
}
std::sort(sum,sum+m+m+1+1,cmp);
for(i=0;i<m+m+1;i++)
printf("%d ",sum[i]);
printf("%d\n",sum[m+m+1]);
}
return 0;
}
問題F:
題目描述
N只小白鼠(1 <= N <= 100),每隻鼠頭上戴著一頂有顏色的帽子。現在稱出每隻白鼠的重量,要求按照白鼠重量從大到小的順序輸出它們頭上帽子的顏色。帽子的顏色用“red”,“blue”等字串來表示。不同的小白鼠可以戴相同顏色的帽子。白鼠的重量用整數表示。
輸入
多案例輸入,每個案例的輸入第一行為一個整數N,表示小白鼠的數目。
下面有N行,每行是一隻白鼠的資訊。第一個為不大於100的正整數,表示白鼠的重量,;第二個為字串,表示白鼠的帽子顏色,字串長度不超過10個字元。
注意:白鼠的重量各不相同。
輸出
每個案例按照白鼠的重量從大到小的順序輸出白鼠的帽子顏色。
樣例輸入
1 79 omi 9 46 lcg 92 cru 37 ceq 54 vhr 17 wus 27 tnv 13 kyr 95 wld 34 qox
樣例輸出
omi wld cru vhr lcg ceq qox tnv wus kyr
#include<cstdio>
#include<algorithm>
#include<cstring>
int main(){
//N(1~100)個小白鼠,兩個值:重量(小等於100)和顏色(十個字元)
//對重量排序,輸出顏色
//二維陣列,排序怎麼辦?
//關鍵點:白鼠的重量各不相同,可以採用那個方法,暫時忘記名字
//執行奔潰 :char*定義常量字串,不能改變
//兩個陣列:放重量,放顏色,再新增一個數組來排序
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int n;
while(scanf("%d",&n)!=-1) {
char a[101][10];
int w[101],t[101];
memset(a,0,sizeof(a));
memset(w,0,sizeof(w));
memset(t,0,sizeof(t));
int i,j;
for(i=0;i<n;i++){
scanf("%d",&w[i]);
scanf("%s",a[w[i]]);
t[w[i]]=1;
// printf("%s",a[w[i]]);
}
for(j=100;j>=0;j--)
if(t[j]==1) //這裡會打出多餘的換行
printf("%s\n",a[j]);
}
return 0;
}
問題G:
題目描述
中位數定義:一組資料按從小到大的順序依次排列,處在中間位置的一個數(或最中間兩個資料的平均數).
給出一組無序整數,求出中位數,如果求最中間兩個數的平均數,向下取整即可(不需要使用浮點數)
輸入
該程式包含多組測試資料,每一組測試資料的第一行為N,代表該組測試資料包含的資料個數,1<=N<=10000.
接著N行為N個數據的輸入,N=0時結束輸入
輸出
輸出中位數,每一組測試資料輸出一行
樣例輸入
1 468 15 501 170 725 479 359 963 465 706 146 282 828 962 492 996 943 0
樣例輸出
468 501
#include<cstdio>
#include<algorithm>
#include<cstring>
const int M=10003;
//int cmp(const void* a,const void *b){
// return *(int*)a-*(int*)b;
bool cmp(int a,int b){
return a<b;
}
int main(){
//分析:找出中位數(整數,向下取整)
//輸入:N位0時結束(1~10000)
//排序: 待定
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int n,a[M];
while(scanf("%d",&n)&&n!=0){
memset(a,0,sizeof(a));
int i;
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
// qsort(a,n,sizeof(int),cmp); //系統禁止呼叫這個玩意兒
std::sort(a,a+n,cmp); //呼叫sort函式不會超時
if(n%2==1)
printf("%d\n",a[n/2]);
else{
int temp=(a[n/2]+a[(n-1)/2])/2;//自動去掉小數部分
printf("%d\n",temp);
}
}
return 0;
}
問題H:
題目描述
輸入10個整數,彼此以空格分隔。重新排序以後輸出(也按空格分隔),要求:
1.先輸出其中的奇數,並按從大到小排列;
2.然後輸出其中的偶數,並按從小到大排列。
輸入
任意排序的10個整數(0~100),彼此以空格分隔。
輸出
可能有多組測試資料,對於每組資料,按照要求排序後輸出,由空格分隔。
樣例輸入
0 56 19 81 59 48 35 90 83 75 17 86 71 51 30 1 9 36 14 16
樣例輸出
83 81 75 59 35 19 0 48 56 90 71 51 17 9 1 14 16 30 36 86
提示
多組資料,注意輸出格式
1. 測試資料可能有很多組,請使用while(cin>>a[0]>>a[1]>>...>>a[9])類似的做法來實現;
2. 輸入資料隨機,有可能相等。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
bool cmp1(int a,int b){
return a>b;
}
bool cmp2(int a,int b){
return a<b;
}
int main(){
//輸入:十個整數
//輸出:奇數從大到小,偶數從小到大,一行,空格分開
//這個和之前的資料讀入不一樣,每次讀一組,按照提示的方法寫
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int a[10],odd[10],even[10]; //空間換時間
while(cin>>a[0]>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6]>>a[7]>>a[8]>>a[9]) { //提示1
int i,t1=0,t2=0;
memset(odd,0,sizeof(odd));
memset(even,0,sizeof(even));
for(i=0;i<10;i++){
if(a[i]%2==0)
even[t2++]=a[i];
else
odd[t1++]=a[i];
}
sort(odd,odd+t1,cmp1);
sort(even,even+t2,cmp2);
for(i=0;i<t1;i++)
cout<<odd[i]<<" ";
for(i=0;i<t2;i++)
cout<<even[i]<<" ";
cout<<endl;
}
return 0;
}
問題I:
題目描述
今天的上機考試雖然有實時的Ranklist,但上面的排名只是根據完成的題數排序,沒有考慮每題的分值,所以並不是最後的排名。給定錄取分數線,請你寫程式找出最後通過分數線的考生,並將他們的成績按降序列印。
輸入
測試輸入包含若干場考試的資訊。每場考試資訊的第1行給出考生人數N ( 0 < N < 1000 )、考題數M ( 0 < M < = 10 )、分數線(正整數)G;第2行排序給出第1題至第M題的正整數分值;以下N行,每行給出一名考生的准考證號(長度不超過20的字串)、該生解決的題目總數m、以及這m道題的題號(題目號由1到M)。
當讀入的考生人數為0時,輸入結束,該場考試不予處理。
輸出
對每場考試,首先在第1行輸出不低於分數線的考生人數n,隨後n行按分數從高到低輸出上線考生的考號與分數,其間用1空格分隔。若有多名考生分數相同,則按他們考號的升序輸出。
樣例輸入
3 5 32 17 10 12 9 15 CS22003 5 1 2 3 4 5 CS22004 3 5 1 3 CS22002 2 1 5 0
樣例輸出
3 CS22003 63 CS22004 44 CS22002 32
提示
這題比較簡單,計算好每個人的分數後按題目要求排序即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1005;
const int M=15;
struct students{
char admission[20];
int total;
int topic[M];
int sum;
}s[N];
bool cmp(students a,students b){
if(a.sum==b.sum)
return strcmp(a.admission,b.admission)<0;
else
return a.sum>b.sum;
}
int main(){
//輸入:人數 N ( 0 < N < 1000 )、考題數M ( 0 < M < = 10 )、分數線(正整數)G
//第2是第1題至第M題的正整數分值;
//以下N行,考生的准考證號(長度不超過20的字串)、解決的題目總數m、以及這m道題的題號(題目號由1到M)。
//考生人數為0時,輸入結束
//輸出: 第1行輸出不低於分數線的考生人數n,
//隨後n行按分數從高到低輸出上線考生的考號與分數,其間用1空格分隔。
//若有多名考生分數相同,則按他們考號的升序輸出。
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int n,m,g,i;
int questions[M];
while(scanf("%d",&n)&&n!=0) {
memset(questions,0,sizeof(questions));
int t=0;
scanf("%d%d",&m,&g);
for(i=1;i<=m;i++){
scanf("%d",&questions[i]);
}
for(i=0;i<n;i++){
scanf("%s%d",s[i].admission,&s[i].total);
for(int j=0;j<s[i].total;j++){
scanf("%d",&s[i].topic[j]);
s[i].sum+=questions[s[i].topic[j]];
}
if(s[i].sum>=g){
t++;
}
}
std:: sort(s,s+n,cmp);
printf("%d\n",t);
for(i=0;i<n;i++){
if(s[i].sum>=g){
printf("%s %d\n",s[i].admission,s[i].sum);
}
}
}
return 0;
}