1. 程式人生 > 其它 >1067 Sort with Swap(0, i) (25 分)(貪心)

1067 Sort with Swap(0, i) (25 分)(貪心)

Given any permutation of the numbers {0, 1, 2,..., N-1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (<=105) followed by a permutation sequence of {0, 1, ..., N-1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:

10 3 5 7 2 6 4 9 0 8 1

Sample Output:

9

題目大意:

給出一個n個數的序列,數字為0~n-1的亂序,每次用兩兩交換的方式而且只能用0和另一個數交換,使序列變成有序的,問最少需要多少步驟。

分析:

1.0號為哨兵, 用哨兵與其他數字交換,使其他數字回到有序的位置(最後有序時所處的位置),則排序完成

2.a[t] = i; 表示t數字當前正在佔著哪一個位置。 (如果想實時監測每個數字的位置,可以用 b 陣列{b[a[i]] = i } 快取一下資料,輸出檢視的)

3.依次遍歷每個位置i,如果當前位置不是與之對應的數字,那麼我們讓這哨兵來去該數執行操作回到正確位置

4.數字如何被哨兵執行操作回到序的位置:

如果哨兵此時不在自己有序的位置上,那就,先讓哨兵去讓他佔的那個位置上的真正應該放的數字回到此位置,即交換哨兵和此數字,我們swap(a[0],a[a0]),直到哨兵在交換的過程中回到了自己的有序位置。字詞再次檢查該位置是不是應該放的數字(別的數字回到有序位置的時候即哨兵執行操作的過程中,有可能讓此位置該有的數字回到位置)。如果此位置不是當前數字,那哨兵和他交換swap(a[0],a[i]),就是讓他先去哨兵的有序位置待一會,等下一輪操作,哨兵會把他交換回來的。如果此位置已經是該數字了,那就什麼都不做。

5.當到達最後一個位置時候,兩種情況 1)。如果第一個數字和最後一個數字都在自己的有序位置 那ok~ 2).哨兵和最後一個數字互相佔著對方的位置,那最後一個數字就是哨兵,交換一次後,哨兵在交換後的位置等待,就是已經回到自己的有序位置,此時排序也是完成的。此過程包括在4裡面了,怕你們不理解,單獨說一下~

原文連結:https://blog.csdn.net/liuchuo/article/details/52264805

柳神程式碼

#include <iostream>
using namespace std;
int main() {
    int n, t, cnt = 0, a[100010];
    cin >> n;
    for(int i = 0; i < n; i++){
    	cin >> t;
    	a[t] = i;
    }
    for(int i = 1; i < n; i++) {
        if(i != a[i]) {
            while(a[0] != 0) {
                swap(a[0],a[a[0]]);
                cnt++;
            }
            if(i != a[i]) {
                swap(a[0],a[i]);
                cnt++;
            }
        }
    }
    cout << cnt;
    return 0;
}

題解

菜雞的我並沒有看懂柳神的分析,下為演算法筆記的解釋,比較易懂一些~



#include <bits/stdc++.h>

using namespace std;
const int maxn=100010;
int pos[maxn]; //存放各數字當前所處的位置編號
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif
    int n,ans=0; //ans表示總交換次數
    scanf("%d",&n);
    int left=n-1,num; //left存放除0以外不在本位上的數的個數
    for(int i=0;i<n;i++){
        scanf("%d",&num);
        pos[num]=i; //num所處的位置為i
        if(num==i&&num!=0){ //如果除0以外有在本位上的數
            left--; //令left減一
        }
    }
    int k=1; //k存放除0以外當前不在本位上的最小的數
    while(left>0){ //只要還有數不在本位上
        //如果0在本位上,則尋找一個當前不在本位上的數與0交換
        if(pos[0]==0){
            while(k<n){
                if(pos[k]!=k){ //找到一個當前不在本位上的數k
                    swap(pos[0],pos[k]); //將k與0交換位置
                    ans++;  //交換位置加1
                    break;   //退出迴圈
                }
                k++; //判斷k+1是否在本位
            }
        }
        //只要0不在本位,就將0所在位置的數的當前所處位置與0的位置進行交換
        while(pos[0]!=0){
            swap(pos[pos[0]],pos[0]); //將0與pos[0]交換
            ans++;  //交換次數加1
            left--; //不在本位上的數的個數減1
        }
    }
    printf("%d\n",ans);
    return 0;
}

本文來自部落格園,作者:勇往直前的力量,轉載請註明原文連結:https://www.cnblogs.com/moonlight1999/p/15613789.html