内排序
1-1.距离排序
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
- 给出三维空间中的n个点(不超过10个),求出n个点两两之间的距离,并按距离由大到小依次输出两个点的坐标及它们之间的距离。
- 输入
- 输入包括两行,第一行包含一个整数n表示点的个数,第二行包含每个点的坐标(坐标都是整数)。点的坐标的范围是0到100,输入数据中不存在坐标相同的点。
- 输出
- 对于大小为n的输入数据,输出n*(n-1)/2行格式如下的距离信息:
(x1,y1,z1)-(x2,y2,z2)=距离
其中距离保留到数点后面2位。
(用cout输出时保留到小数点后2位的方法:cout<<fixed<<setprecision(2)<<x) - 样例输入
-
4 0 0 0 1 0 0 1 1 0 1 1 1
- 样例输出
(0,0,0)-(1,1,1)=1.73 (0,0,0)-(1,1,0)=1.41 (1,0,0)-(1,1,1)=1.41 (0,0,0)-(1,0,0)=1.00 (1,0,0)-(1,1,0)=1.00 (1,1,0)-(1,1,1)=1.00
我的代码
1 # include <cstdio> 2 # include <algorithm> 3 # include <cmath> 4 using namespace std; 5 6 //node 7 typedef struct{ 8 int x, y, z; 9 }NODE; 10 //edge 11 typedef struct{ 12 int n1, n2, l; 13 } EDGE; 14 15 int N, i, j, k = 0; 16 NODE * n; 17 EDGE * e; 18 19 //compare if e1 longer than e2 20 bool cmp(EDGE e1, EDGE e2){ 21 return e1.l > e2.l; 22 } 23 //calculate edge's length between node n1 & n2 24 int Len(int n1, int n2){ 25 int x = n[n1].x - n[n2].x, 26 y = n[n1].y - n[n2].y, 27 z = n[n1].z - n[n2].z; 28 return x*x + y*y + z*z; 29 } 30 //bubble sort 31 void MySort(){ 32 EDGE t; 33 for(i=0; i<k-1; ++i){ 34 for(j=k-1; j>i; --j){ 35 //edge[j] > edge[j-1] 36 if(cmp(e[j], e[j-1])){ 37 t = e[j]; 38 e[j] = e[j-1]; 39 e[j-1] = t; 40 } 41 } 42 } 43 } 44 //print result 45 void MyPrint(int m){ 46 int n1 = e[m].n1, n2 = e[m].n2, l = e[m].l; 47 printf("(%d,%d,%d)-(%d,%d,%d)=%.2lf\n", 48 n[n1].x, n[n1].y, n[n1].z, 49 n[n2].x, n[n2].y, n[n2].z, sqrt((double)l)); 50 } 51 52 int main(){ 53 //initialize 54 scanf("%d", &N); 55 n = new NODE[N+2]; 56 e = new EDGE[N*(N+1)/2+2]; 57 for(i=0; i<N; ++i) 58 scanf("%d %d %d", &n[i].x, &n[i].y, & n[i].z); 59 //calculate edges' length 60 for(i=0; i<N-1; ++i) 61 for(j=i+1; j<N; ++j){ 62 e[k].n1 = i; 63 e[k].n2 = j; 64 e[k].l = Len(i, j); 65 k++; 66 } 67 //bubble sort 68 MySort(); 69 //print result 70 for(i=0; i<k; ++i) 71 MyPrint(i); 72 //delete 73 delete [] n; 74 delete [] e; 75 return 0; 76 }
1-2.寻找中位数
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
在N(1<=N<10,000且N为奇数)个数中,找到中位数。
- 输入
- 第1行:N
第2至N+1行:每行是一个整数 - 输出
- 第一行:中位数
- 样例输入
-
5 2 4 1 3 5
- 样例输出
3
我的代码
1 # include <cstdio> 2 # include <algorithm> 3 using namespace std; 4 5 int main(){ 6 int n, a[10010]; 7 scanf("%d", &n); 8 for(int i = 0; i < n; ++i) 9 scanf("%d", a + i); 10 sort(a, a + n); 11 printf("%d", a[n/2]); 12 return 0; 13 }
1-3.数组取数
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
有一个整数数组A和一个目标整数T,希望从A中没有放回地取出两个数,使得两个数之差等于T。请问有多少种不同的取法?(取出的两个数分别相等时视为同一种取法)
- 输入
- 输入由两行组成。第一行为两个整型范围内的整数N和T,N为数组长度(N的范围是[2,100000]),T为目标整数。第二行为N个整数,表示数组A,每个整数的范围是[-1000000,1000000]。
- 输出
- A中取出两个数之差为T的不同的取法的数目。
- 样例输入
-
6 1 1 3 2 1 2 2
- 样例输出
-
2
我的代码
1 # include <cstdio> 2 # include <iostream> 3 # include <algorithm> 4 using namespace std; 5 6 int main(){ 7 int n, t, * a, cur, ans = 0; 8 scanf("%d %d", &n, &t); 9 if(t < 0) t = -t; 10 a = new int[n+1]; 11 for(int i = 0; i < n; ++i) 12 scanf("%d", a + i); 13 sort(a, a + n); 14 for(int i = 0; i < n; ){ 15 cur = a[i]; 16 for(int j = i + 1; j < n; ++j){ 17 if(a[j] - cur == t){ 18 ans++; 19 break; 20 } 21 else if(a[j] - cur > t) 22 break; 23 } 24 for(i = i + 1 ; a[i] == cur && i < n; ++i); 25 } 26 printf("%d\n", ans); 27 delete [] a; 28 return 0; 29 }
2-1.Freda的越野跑
总时间限制:
- 1000ms
- 内存限制:
- 262144kB
- 描述
-
Freda报名参加了学校的越野跑。越野跑共有N人参加,在一条笔直的道路上进行。这N个人在起点处站成一列,相邻两个人之间保持一定的间距。比赛开始后,这N个人同时沿着道路向相同的方向跑去。换句话说,这N个人可以看作x轴上的N个点,在比赛开始后,它们同时向x轴正方向移动。
假设越野跑的距离足够远,这N个人的速度各不相同且保持匀速运动,那么会有多少对参赛者之间发生“赶超”的事件呢? - 输入
- 第一行1个整数N。
第二行为N 个非负整数,按从前到后的顺序给出每个人的跑步速度。
对于50%的数据,2<=N<=1000。
对于100%的数据,2<=N<=100000。 - 输出
- 一个整数,表示有多少对参赛者之间发生赶超事件。
- 样例输入
-
5 1 3 10 8 5
- 样例输出
-
7
- 提示
- 我们把这5个人依次编号为A,B,C,D,E,速度分别为1,3,10,8,5。
在跑步过程中:
B,C,D,E均会超过A,因为他们的速度都比A快;
C,D,E都会超过B,因为他们的速度都比B快;
C,D,E之间不会发生赶超,因为速度快的起跑时就在前边。
我的代码
1 # include <cstdio> 2 # include <iostream> 3 # include <algorithm> 4 using namespace std; 5 6 int n, a[100010]; 7 long long ans = 0; 8 9 void Merge(int s, int m, int e){ 10 int b[100010], i = s, j = m+1, k = s; 11 while(i <= m && j <= e){ 12 if(a[i] >= a[j]) //如果相等,取a[i],以保证稳定性 13 b[k++] = a[i++]; 14 else{ 15 b[k++] = a[j++]; 16 ans += j - k; //在位置j的选手超过了j-k个人,来到了位置k 17 } 18 } 19 while(i <= m) b[k++] = a[i++]; 20 while(j <= e) b[k++] = a[j++]; 21 for(k = s; k <= e; ++k) 22 a[k] = b[k]; 23 return; 24 } 25 26 void MergeSort(int s, int e){ 27 if(s >= e) return; 28 int mid = (s + e) / 2; 29 MergeSort(s, mid); 30 MergeSort(mid + 1, e); 31 Merge(s, mid, e); 32 return; 33 } 34 35 int main(){ 36 scanf("%d", &n); 37 for(int i = 0; i < n; ++i) 38 scanf("%d", a + i); 39 MergeSort(0, n-1); 40 printf("%lld\n", ans); 41 return 0; 42 }
2-2.The Peanuts
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
- Mr. Robinson and his pet monkey Dodo love peanuts very much. One day while they were having a walk on a country road, Dodo found a sign by the road, pasted with a small piece of paper, saying "Free Peanuts Here! " You can imagine how happy Mr. Robinson and Dodo were.
There was a peanut field on one side of the road. The peanuts were planted on the intersecting points of a grid as shown in Figure-1. At each point, there are either zero or more peanuts. For example, in Figure-2, only four points have more than zero peanuts, and the numbers are 15, 13, 9 and 7 respectively. One could only walk from an intersection point to one of the four adjacent points, taking one unit of time. It also takes one unit of time to do one of the following: to walk from the road to the field, to walk from the field to the road, or pick peanuts on a point.
According to Mr. Robinson's requirement, Dodo should go to the plant with the most peanuts first. After picking them, he should then go to the next plant with the most peanuts, and so on. Mr. Robinson was not so patient as to wait for Dodo to pick all the peanuts and he asked Dodo to return to the road in a certain period of time. For example, Dodo could pick 37 peanuts within 21 units of time in the situation given in Figure-2.
Your task is, given the distribution of the peanuts and a certain period of time, tell how many peanuts Dodo could pick. You can assume that each point contains a different amount of peanuts, except 0, which may appear more than once. - 输入
- The first line of input contains the test case number T (1 <= T <= 20). For each test case, the first line contains three integers, M, N and K (1 <= M, N <= 50, 0 <= K <= 20000). Each of the following M lines contain N integers. None of the integers will exceed 3000. (M * N) describes the peanut field. The j-th integer X in the i-th line means there are X peanuts on the point (i, j). K means Dodo must return to the road in K units of time.
- 输出
- For each test case, print one line containing the amount of peanuts Dodo can pick.
- 样例输入
-
2 6 7 21 0 0 0 0 0 0 0 0 0 0 0 13 0 0 0 0 0 0 0 0 7 0 15 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 6 7 20 0 0 0 0 0 0 0 0 0 0 0 13 0 0 0 0 0 0 0 0 7 0 15 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0
- 样例输出
-
37 28
我的代码
1 # include <cstdio> 2 # include <algorithm> 3 using namespace std; 4 5 typedef struct { 6 int i, j, pea; 7 } Point; 8 9 bool cmp(Point p1, Point p2){ 10 return p1.pea > p2.pea; 11 } 12 13 int myabs(int num){ 14 if(num < 0) return -num; 15 else return num; 16 } 17 18 int T, M, N, K; 19 int cnt, ans; 20 Point p[2510]; 21 22 void Init(){ 23 scanf("%d %d %d", &M, &N, &K); 24 cnt = 0; 25 ans = 0; 26 int pea; 27 for(int i = 0; i < M; ++i) 28 for(int j = 0; j < N; ++j){ 29 scanf("%d", &pea); 30 //record points with peanuts > 0 31 if(pea){ 32 p[cnt].i = i; 33 p[cnt].j = j; 34 p[cnt].pea = pea; 35 cnt++; 36 } 37 } 38 } 39 40 void PickPeanut(){ 41 //current: position [i][j], target p[cur] 42 //time: initially time = 1 (road to field) 43 int i = 0, j = p[0].j, cur = 0, time = 1; 44 while(cur < cnt && time <= K){ 45 time += myabs(i - p[cur].i) + myabs(j - p[cur].j) + 1; 46 if(time + p[cur].i + 1 <= K) //can fetch p[cur] 47 ans += p[cur].pea; 48 else 49 break; 50 i = p[cur].i; 51 j = p[cur].j; 52 ++cur; 53 } 54 return; 55 } 56 57 int main(){ 58 scanf("%d", &T); 59 while(T--){ 60 Init(); 61 sort(p, p + cnt, cmp); 62 PickPeanut(); 63 printf("%d\n", ans); 64 } 65 return 0; 66 }
2-3.DNA排序
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
现在有一些长度相等的DNA串(只由ACGT四个字母组成),请将它们按照逆序对的数量多少排序。逆序对指的是字符串A中的两个字符A[i]、A[j],具有i < j 且 A[i] > A[j] 的性质。如字符串”ATCG“中,T和C是一个逆序对,T和G是另一个逆序对,这个字符串的逆序对数为2。
- 输入
- 第1行:两个整数n和m,n(0<n<=50)表示字符串长度,m(0<m<=100)表示字符串数量
第2至m+1行:每行是一个长度为n的字符串 - 输出
- 按逆序对数从少到多输出字符串,逆序对数一样多的字符串按照输入的顺序输出。
- 样例输入
-
10 6 AACATGAAGG TTTTGGCCAA TTTGGCCAAA GATCAGATTT CCCGGGGGGA ATCGATGCAT
- 样例输出
-
CCCGGGGGGA AACATGAAGG GATCAGATTT ATCGATGCAT TTTTGGCCAA TTTGGCCAAA
我的代码
1 # include <cstdio> 2 # include <string.h> 3 # include <algorithm> 4 using namespace std; 5 6 typedef struct{ 7 char s[55]; 8 int n; 9 } String; 10 11 bool cmp(String s1, String s2){ 12 return s1.n < s2.n; 13 } 14 15 String str[105]; 16 char s[55]; 17 int m, n; 18 19 int Merge(int st, int mid, int end){ 20 int i = st, j = mid + 1, k = st, ans = 0; 21 char s1[55]; 22 while(i <= mid && j <= end){ 23 if(s[i] <= s[j]) 24 s1[k++] = s[i++]; 25 else{ 26 s1[k++] = s[j++]; 27 ans += j-k; 28 } 29 } 30 while(i <= mid) s1[k++] = s[i++]; 31 while(j <= end) s1[k++] = s[j++]; 32 for(k = st; k <= end; ++k) 33 s[k] = s1[k]; 34 return ans; 35 } 36 37 int MergeSort(int st, int e){ 38 if(st >= e) return 0; 39 int mid = (st + e) / 2; 40 return MergeSort(st, mid) + MergeSort(mid+1, e) + Merge(st, mid, e); 41 } 42 43 int main(){ 44 scanf("%d %d", &n, &m); 45 for(int i = 0; i < m; ++i){ 46 scanf("%s", str[i].s); 47 strcpy(s, str[i].s); 48 str[i].n = MergeSort(0, n-1); 49 } 50 sort(str, str + m, cmp); 51 for(int i = 0; i < m; ++i) 52 printf("%s\n", str[i].s); 53 return 0; 54 }
外排序
1.置换选择排序
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
给定初始整数顺串,以及大小固定并且初始元素已知的二叉最小堆(为完全二叉树或类似完全二叉树,且父元素键值总小于等于任何一个子结点的键值),要求利用堆实现置换选择排序,并输出第一个顺串。例如给定初始顺串29,14,35,13,以及堆(记为16 19 31 25 21 56 40), 置换选择排序得到的第一个顺串为16 19 21 25。
- 输入
- 第一行包含两个整数,m为初始顺串的数的个数,n为二叉最小堆的大小
第二行包含m个整数,即初始顺串
第三行包含n个整数,即已经建好的堆的元素(有序,按照从堆顶到堆底,从左到右的顺序) - 输出
- 输出包含一行,即第一个顺串。
- 样例输入
-
4 7 29 14 35 13 16 19 31 25 21 56 40
- 样例输出
-
16 19 21 25
我的代码
1 # include <iostream> 2 using namespace std; 3 4 int m, n, * heap, * num; 5 6 void Init(){ 7 cin >> m >> n; 8 heap = new int [n+1]; 9 num = new int [m+1]; 10 for(int i=0; i<m; ++i) 11 cin >> num[i]; 12 for(int i=0; i<n; ++i) 13 cin >> heap[i]; 14 } 15 16 void Exch(int i, int j){ 17 int tmp = heap[i]; 18 heap[i] = heap[j]; 19 heap[j] = tmp; 20 } 21 22 void ShiftDown(){ 23 int cur = 0, s1 = 1, s2 = 2; 24 while(s2 < n){ 25 if(heap[cur] <= heap[s1] && heap[cur] <= heap[s2]) 26 return; //heap is min heap already 27 if(heap[s1] > heap[s2]){ 28 Exch(cur, s2); 29 cur = s2; 30 } 31 else{ 32 Exch(cur, s1); 33 cur = s1; 34 } 35 s1 = cur * 2 + 1; 36 s2 = s1 + 1; 37 } 38 if(s1 < n && heap[s1] < heap[cur]) 39 Exch(cur, s1); 40 return; 41 } 42 43 void Insert(){ 44 //attention! n should > 0 45 for(int i=0; i<m && n; ++i){ 46 cout << heap[0] << ' '; 47 if(num[i] >= heap[0]) 48 heap[0] = num[i]; 49 else 50 heap[0] = heap[--n]; 51 ShiftDown(); 52 } 53 } 54 55 void Dele(){ 56 delete [] heap; 57 delete [] num; 58 } 59 60 int main(){ 61 Init(); 62 Insert(); 63 Dele(); 64 return 0; 65 }
2.败方树
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
-
给定一个整数数组,要求对数组中的元素构建败方树(数组相邻元素两两比较,从第一个元素开始)。之后修改数组中的元素,要求输出初始构建以及修改后得到的败方树的所有内部结点代表的整数(从左到右从上到下输出)
- 输入
- 第一行为数组的元素个数n和修改的次数m。
第二行为n个整数,即数组的元素。
接下来m行代表m次修改操作,每次操作修改数组中的一个元素,每一行包括两个整数,第一个为被修改元素在数组中的标号,第二个为修改之后的元素值。 - 输出
- 输出m+1行。
第一行为初始构建的败方树的所有内部结点代表的整数(按照树的结点从左到右从上到下的顺序输出)
接下来m行为接下来m次修改后得到的败方树的所有内部结点代表的整数(按照树的结点从左到右从上到下的顺序输出) - 样例输入
-
8 1 10 9 20 6 16 12 90 17 3 15
- 样例输出
-
6 12 9 17 10 20 16 90 9 12 15 17 10 20 16 90
我的代码
1 # include <iostream> 2 using namespace std; 3 4 struct LoserTree{ 5 int n; // elements to be compared: n 6 int LowExt; // lowest external elements number: LowExt 7 int s; // lowest internal level elements: s 8 int offset; // total nodes numbers except lowest level 9 int * tree; // loser tree 10 int * ele; // elements to be compared 11 int winner(int c1, int c2); // return winner index 12 int loser(int c1, int c2); // return loser index 13 void init(int _n, int * _ele); // initialize loser tree 14 void play(int p, int c1, int c2); // compare ele[c1] & [c2], their parent is p 15 void build(); // rebuile loser tree 16 void print(); // print tree 17 void dele(); // delete tree 18 }; 19 20 int LoserTree::winner(int c1, int c2){ 21 if(ele[c1] < ele[c2]) return c1; 22 else return c2; 23 } 24 25 int LoserTree::loser(int c1, int c2){ 26 if(ele[c1] < ele[c2]) return c2; 27 else return c1; 28 } 29 30 void LoserTree::init(int _n, int * _ele){ 31 ele = _ele; 32 n = _n; 33 tree = new int [n]; 34 for(s = 1; s*2 < n; s *= 2); 35 offset = 2 * s - 1; 36 LowExt = 2 * (n - s); 37 } 38 39 void LoserTree::play(int p, int c1, int c2){ 40 int lastwin = winner(c1, c2), tempwin; 41 tree[p] = loser(c1, c2); 42 while(p > 1 && p % 2 == 1){ // right subtree goes up 43 tempwin = winner(lastwin, tree[p/2]); 44 tree[p/2] = loser(lastwin, tree[p/2]); 45 lastwin = tempwin; 46 p /= 2; 47 } 48 tree[p/2] = lastwin; // p = 1, or tree[p] is a left sibling 49 } 50 51 void LoserTree::build(){ 52 int i; 53 // lowest level elements play 54 for(i = 2; i <= LowExt; i += 2) 55 play((offset+i)/2, i-1, i); 56 // one inner node vs one element 57 if(n % 2){ 58 play(n/2, tree[n-1], LowExt+1); 59 i = LowExt + 3; 60 } 61 else i = LowExt + 2; 62 // the last second level elements play 63 for( ; i <= n; i += 2) 64 play((i-LowExt+n-1)/2, i-1, i); 65 } 66 67 void LoserTree::print(){ 68 for(int i = 0; i < n; ++i) 69 cout << ele[tree[i]] << ' '; 70 cout << endl; 71 } 72 73 void LoserTree::dele(){ 74 delete [] tree; 75 } 76 77 int main(){ 78 int n, m, * ele, index, val; 79 LoserTree MyTree; 80 cin >> n >> m; 81 ele = new int [n+2]; 82 for(int i=1; i<=n; ++i) 83 cin >> ele[i]; 84 MyTree.init(n, ele); 85 MyTree.build(); 86 MyTree.print(); 87 for(int i=0; i<m; ++i){ 88 cin >> index >> val; 89 ele[index+1] = val; // change value if ele[index] 90 MyTree.build(); // rebuild 91 MyTree.print(); 92 } 93 MyTree.dele(); 94 delete [] ele; // don't dorget!!! 95 return 0; 96 }