DS实验题 Inversion
題目:
解題過程:
第一次做這題的時候,很自然的想到了冒泡和選擇,我交的代碼是用選擇寫的。基本全WA(攤手)。
貼上第一次的代碼:
// // main.cpp // sequenceschange // // Created by wasdns on 16/10/7. // Copyright ? 2016年 wasdns. All rights reserved. // #include <iostream> #include <string> #include <cstdio> #include <algorithm> using namespace std; int seq[50005]; int main() { int i, j, n; cin >> n; for (i = 0; i < n; i++) { cin >> seq[i]; } int cnt = 0; int t = 0; for (i = n - 1; i >= 0; i--) { for (j = i - 1; j >= 0; j--) { if(seq[i] > seq[j]) break; cnt ++; t = seq[i]; seq[i] = seq[j]; seq[j] = t; } } cout << cnt << endl; return 0; }冒泡和選擇,這兩種算法的問題在于,會有重復比較的元素,不滿足題意要求的最小比較次數。
本題也是比較經典的逆序對問題,解決的方法是插入排序。
這里給出鏈接參考:九大排序算法再總結
第二種算法(分治加插入排序)思想:
給出一個數組,以及給出左邊界l右邊界r代表需要排序的序列范圍,將這個序列不斷分成兩個部分,直到遞歸到單個元素再向上進行Union的操作,Union的操作通過插入排序來實現。
// // main.cpp // 逆序對 // // Created by wasdns on 16/12/1. // Copyright ? 2016年 wasdns. All rights reserved. //#include <iostream> #include <cstdio> #include <algorithm> using namespace std;int a[50010];/*用來debug的函數 */ void printa(int l, int r) {for (int i = l; i <= r; i++) {printf("%d ", a[i]);}printf("\n"); }/*交換函數 */ void swap(int i, int j) {int t = a[i];a[i] = a[j];a[j] = t; }/*Union 兩部分合并函數 */ int Union(int l, int r) {if (l == r) return 0;int i, p1, p2; //p1指向序列A的元素,p2指向序列B的元素int cnt = 0; //記錄比較次數for (i = l+1; i <= r; i++){p1 = i-1;p2 = i;while (a[p2] < a[p1] && p1 != 0){swap(p1, p2);cnt++;p1--;p2--;}}return cnt; }/*排序算法主體 */int divsort(int l, int r) {//printf("div:");//printa(l, r);if (l == r) return 0;int cnt = 0;int mid = (l+r) / 2;int ltime = divsort(l, mid);int rtime = divsort(mid+1, r);cnt += ltime;cnt += rtime;cnt += Union(l, r);//printf("afterdiv:");//printa(l, r);return cnt; }void Initial(int n) {for (int i = 1; i <= n; i++){scanf("%d", &a[i]);} }int main() {int n;cin >> n;Initial(n);int cnt;cnt = divsort(1, n);printf("%d\n", cnt);return 0; }結果是部分點TLE:
分析下算法復雜度:選擇最后一次的Union操作,最壞情況下一共有50000個節點,從l到mid是25000個排好序的元素,從mid開始到r有25000個無序的元素,將后面的25000個元素插入到前面的序列,>=25000*25000的時間;復雜度為O(n^2),因此TLE。
于是選擇使用歸并排序,之前的操作和算法二的思想類似,但是修改了Union的操作:維護一個數組b,使用兩個指針指向兩個待排序的序列,把這兩個指針分別指向的元素進行比較,較小的元素加入到b中,指向它的指針后移,直到到達邊界。
另外一個需要care的點是cnt的計數:
倘若先前的序列叫做A,后面的序列叫做B,當判斷出B序列的當前指向元素較小進入數組b時,相當于是通過mid+1-p1(p1是當前指針指向A的位置)次比較的操作將元素移至有序的位置。
int Union(int l, int r) {if (l == r) return 0;int mid = (l+r) / 2;int i, p1 = l, p2 = mid+1;int cnt = 0;int tot = 1;while (p1 <= mid && p2 <= r){if (a[p1] > a[p2]) {cnt += mid+1-p1; //相當于比較了mid+1-p1次b[tot++] = a[p2++];}else b[tot++] = a[p1++];}if (p1 > mid && p2 <= r){while (p2 <= r){b[tot++] = a[p2++];}}else if (p2 > r && p1 <= mid){while (p1 <= mid){b[tot++] = a[p1++];}}for (i = l; i <= r; i++){a[i] = b[i-l+1];}return cnt; }int divsort(int l, int r) {//printf("div:");//printa(l, r);if (l == r) return 0;int cnt = 0;int mid = (l+r) / 2;int ltime = divsort(l, mid);int rtime = divsort(mid+1, r);cnt += ltime;cnt += rtime;cnt += Union(l, r);//printf("afterdiv:");//printa(l, r);return cnt; }算法復雜度:O(n)
2016/12/2
轉載于:https://www.cnblogs.com/qq952693358/p/6124225.html
總結
以上是生活随笔為你收集整理的DS实验题 Inversion的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ⭐register_chrdev、reg
- 下一篇: BOM操作写法实例