P1271 【深基9.例1】选举学生会 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> int m, n, temp;int vote[1000 ];int main () { std::cin >> n >> m; for (int i = 0 ; i < m; i++){ std::cin >> temp; vote[temp]++; } for (int i = 1 ; i <= n; i++){ while (vote[i]--){ std::cout << i << " " ; } } return 0 ; }
P1177 【模板】排序 排序题,写一个快排练练手(填进去后超时了)
查了一下资料发现经典快排是会超时的(以第一个作为标签元素)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> void qsort (int a[], int left, int right) { int i = left, j = right, key = a[i]; while (i < j){ while (i < j && a[j] >= key){ j--; } a[i] = a[j]; while (i < j && a[i] <= key){ i++; } a[j] = a[i]; } a[i] = key; if ((i - 1 ) > left){ qsort (a, left, i - 1 ); } if (right > (i + 1 )){ qsort (a, i + 1 , right); } return ; } int a[200000 ];int n;int main () { scanf ("%d" , &n); for (int i = 0 ;i < n; i++){ scanf ("%d" , &a[i]); } qsort (a, 0 , n-1 ); for (int i = 0 ;i < n; i++){ printf ("%d " , a[i]); } return 0 ; }
小改了一下还是有问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> int a[200000 ];int n;void qsort (int left, int right) { std::swap (a[left], a[(left + right) / 2 ]); int i = left, j = right, key = a[i]; while (i < j){ while (i < j && a[j] >= key){ j--; } a[i] = a[j]; while (i < j && a[i] <= key){ i++; } a[j] = a[i]; } a[i] = key; if ((i - 1 ) > left){ qsort (left, i - 1 ); } if (right > (i + 1 )){ qsort (i + 1 , right); } return ; } int main () { scanf ("%d" , &n); for (int i = 0 ;i < n; i++){ scanf ("%d" , &a[i]); } qsort (0 , n-1 ); for (int i = 0 ;i < n; i++){ printf ("%d " , a[i]); } return 0 ; }
P1923 【深基9.例4】求第 k 小的数 这里用std输入流太慢了,会卡时间,故用scanf
本题的思路是分治,用快排原理,先随便找一个数作为中间值,然后将数依次在中间值左右排开,此时中间值的下标就是确切下标;
find函数比较中间值和k,k较小则在中间值左边部分寻找,同理右边或者相等时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <iostream> int a[5000010 ];int qsort (int left, int right) { int key = a[left]; while (left < right){ while (left < right && a[right] >= key){ right--; } a[left] = a[right]; while (left < right && a[left] <= key){ left++; } a[right] = a[left]; } a[left] = key; return left; } int find (int left, int right, int k) { int temp = qsort (left, right); if (k == temp){ std::cout << a[k]; } else if (k < temp){ find (left, temp - 1 , k); } else { find (temp + 1 , right, k); } return 0 ; } int main () { int n, k; std::cin >> n >> k; for (int i = 0 ;i < n; i++){ scanf ("%d" , &a[i]); } find (0 , n-1 , k); return 0 ; }
P1059 [NOIP2006 普及组] 明明的随机数 用STL的一个库模板会很好写,set就是一个有序的集合,不允许出现重复元素而且会自行从小到大排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <set> int m, temp;std::set<int > s; int main () { std::cin >> m; for (int i = 0 ; i < m; i++){ std::cin >> temp; s.insert (temp); } std::cout << s.size () << "\n" ; while (!s.empty ()){ std::cout << *s.begin () << " " ; s.erase (s.begin ()); } return 0 ; }
也可以用桶排序,这个排序的时间复杂度是n,适用于序列个数较小的排序。
桶排序的思路就是设定一个有大小的范围数组,例如此题的随机数不超过1000,于是就设置一个大小不小于1000的数组都初始化为0,然后将下标和输入数相同的元素值+1(重复时忽略),最后根据下标从小到大遍历数组,为1就输出下标,达到从小到大排序的目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> int m, temp, cnt = 0 , random[1010 ] = {0 };int main () { std::cin >> m; for (int i = 0 ; i < m; i++){ std::cin >> temp; if (!random[temp]){ random[temp]++; cnt++; } } std::cout << cnt << "\n" ; for (int i = 1 ; i <= 1000 ; i++){ if (random[i]){ std::cout << i << " " ; } } return 0 ; }
P1093 [NOIP2007 普及组] 奖学金 设置一个结构体,在里面存储各种成绩信息。
然后写一个cmp函数来传入sort,重构比较方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <iostream> #include <algorithm> struct score { int chinese, math, english, num, sum; }stus[310 ]; int number;bool cmp (score a, score b) { if (a.sum > b.sum){ return true ; } else if (a.sum < b.sum){ return false ; } else { if (a.chinese > b.chinese){ return true ; } else if (a.chinese < b.chinese){ return false ; } else { if (a.num < b.num){ return true ; } else { return false ; } } } } int main () { std::cin >> number; for (int i = 1 ;i <= number; i++){ std::cin >> stus[i].chinese >> stus[i].math >> stus[i].english; stus[i].sum = stus[i].chinese + stus[i].math + stus[i].english; stus[i].num = i; } std::sort (stus + 1 , stus + number + 1 , cmp); for (int i = 1 ; i <=5 ; i++){ std::cout << stus[i].num << " " << stus[i].sum << "\n" ; } return 0 ; }
P1781 宇宙总统 和上题的思路差不多,也是重构比较函数,这里由于票数数字太大用字符串存储。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <algorithm> struct person { int number; std::string votes; }president[21 ]; bool cmp (person a, person b) { if (a.votes.length () > b.votes.length ()){ return true ; } else if (a.votes.length () < b.votes.length ()){ return false ; } else { for (int i = 0 ;i < a.votes.length (); i++){ if (a.votes[i] > b.votes[i]){ break ; } if (a.votes[i] < b.votes[i]){ return false ; } } return true ; } } int main () { int n; std::cin >> n; for (int i = 1 ;i <= n; i++){ std::cin >> president[i].votes; president[i].number = i; } std::sort (president + 1 , president + n + 1 , cmp); std::cout << president[1 ].number << "\n" << president[1 ].votes; return 0 ; }
[USACO07DEC] Bookshelf B 很简单的题但是很长阅读理解,一开始以为是什么背包问题,呃呃。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <algorithm> int cows_high[20010 ];int N, B, sum = 0 ;bool cmp (int a, int b) { return a > b; } int main () { std::cin >> N >> B; for (int i = 1 ; i <= N; i++){ std::cin >> cows_high[i]; } std::sort (cows_high + 1 , cows_high + N + 1 , cmp); int i = 1 ; while (sum < B){ sum += cows_high[i]; i++; } std::cout << (i - 1 ); return 0 ; }
车厢重组 一道冒泡排序题,输出交换的次数就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> #include <algorithm> int carriages[10010 ];int n, cnt = 0 ;int main () { std::cin >> n; for (int i = 1 ; i <= n; i++){ std::cin >> carriages[i]; } for (int i = 0 ; i < n; i++){ for (int j = 1 ; j < n - i; j++){ if (carriages[j] > carriages[j + 1 ]){ std::swap (carriages[j], carriages[j + 1 ]); cnt++ ; } } } std::cout << cnt; return 0 ; }
欢乐的跳 计算前后差然后排序,若是从1到n-1的公差为1的等差数列,则为jolly
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #include <algorithm> #include <math.h> int n, temp_a = 0 , temp_b = 0 ;int sub[1010 ];int main () { std::cin >> n; for (int i = 0 ; i < n; i++){ temp_b = temp_a; std::cin >> temp_a; sub[i] = fabs (temp_a - temp_b); } std::sort (sub + 1 , sub + n); for (int i = 1 ; i < n; i++){ if (sub[i] != i){ std::cout << "Not jolly" ; return 0 ; } } std::cout << "Jolly" ; return 0 ; }
P1068 [NOIP2009 普及组] 分数线划定 这题有个小坑,是先根据排名推断出分数,再根据分数划分人,我先入为主直接根据排名划分人了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <iostream> #include <algorithm> int m = 0 , n = 0 ;struct per { int number; int score; }pers[5010 ]; bool cmp (per a, per b) { if (a.score > b.score){ return true ; } else if (a.score < b.score){ return false ; } else { return a.number < b.number; } } int main () { std::cin >> n >> m; m = m * 1.5 ; for (int i = 1 ; i <= n; i++){ std::cin >> pers[i].number >> pers[i].score; } std::sort (pers + 1 , pers + 1 + n, cmp); int i = 1 , line_score = pers[m].score; while (pers[m+1 ].score == line_score){ m++; } std::cout << line_score << " " << m << '\n' ; while (pers[i].score >= line_score){ std::cout << pers[i].number << " " << pers[i].score; std::cout << '\n' ; i++; } return 0 ; }
P5143 攀爬者 很无聊的计算题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <iostream> #include <algorithm> #include <math.h> int n;double temp, sum = 0 , x, y, z;struct point { int x, y, z; }points[50010 ]; bool cmp (point a, point b) { return a.z < b.z; } int main () { std::cin >> n; for (int i = 1 ; i <= n; i++){ std::cin >> points[i].x >> points[i].y >> points[i].z; } std::sort (points + 1 , points + 1 + n, cmp); for (int i = 1 ; i < n; i++){ x = pow ((points[i].x - points[i+1 ].x), 2 ); y = pow ((points[i].y - points[i+1 ].y), 2 ); z = pow ((points[i].z - points[i+1 ].z), 2 ); temp = sqrt (x + y + z); sum += temp; } printf ("%.3lf" , sum); return 0 ; }
P1012 [NOIP1998 提高组] 拼数 一开始以为是从大到小排个序然后组合,后来发现是按照高位优先排序的。
正常来说把数字看成字符串然后遍历比较排序就好了。
有个特殊情况就是,两个数的前几项都相同,比如321 和 32,组合成32321时大
但是329 和 32 则是组成 32932比较大,究其原因就是长的那个数最后一项是否大于短的那个数的第一项,若是则长的数较大,反之,由于长短数的第一项相同,直接比较长数的第一项和最后一项就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> #include <algorithm> int n;std::string a[25 ]; bool cmp (std::string a, std::string b) { int len_a = a.length (), len_b = b.length (); int len = std::min (len_a, len_b); for (int i = 0 ; i < len; i++){ if (a[i] > b[i]){ return true ; } else if (a[i] < b[i]){ return false ; } } if (len_a > len_b){ return a[len_a - 1 ] > a[0 ]; } else if (len_a < len_b){ return b[len_a - 1 ] < b[0 ]; } else { return true ; } } int main () { std::cin >> n; for (int i = 0 ;i < n; i++){ std::cin >> a[i]; } std::sort (a, a + n, cmp); for (int i = 0 ;i < n; i++){ std::cout << a[i]; } return 0 ; }