1. 程式人生 > >【2018黑龍江省賽】UPC-7224 The puzzle(任意兩數交換排序次數)

【2018黑龍江省賽】UPC-7224 The puzzle(任意兩數交換排序次數)

題目描述 Kayaking is playing a puzzle game containing n different blocks. He marks the blocks with integers from 1 to n, which show the blocks’ original positions. Each time he can exchange two blocks and he wants to know how many times he needs at least to restore the puzzle.

輸入 The input starts with one line contains exactly one positive integer T which is the number of test cases. Each test case contains two lines. The first line contains an integer, which indicates the number of puzzle pieces. The second line contains n different integers, the i-th number means the mark of the block in the i-th position.

輸出 For each test case, output one line with one number represents the minimum operations.

樣例輸入 2 4 2 3 4 1 4 2 1 4 3

樣例輸出 3 2

提示 1≤T≤20,1≤n≤100000 題意: 給出一個序列,一個操作,選擇任意兩個數做一次位置交換,需要交換幾次使之有序。

題解: 如果是相鄰兩數交換那很明顯就是個求逆序數的題,而這裡是任意兩數交換,可以知道,每個數都是唯一的,那麼每個數都有自己的位置,他們經過一些兩兩交換後導致無序,也就是給出的序列的模樣。那麼將這個過程逆回去暴力模擬,就可以得到有序序列,兩兩交換是在一些數範圍內的,也就是說交換的操作肯定會出現環,那麼其實就是每個數找打自己改在的位置,然後看自己該在的位置的數是誰,再去找那個數改在的位置,這樣不斷迭代會找到一個環,這個環中數的個數-1就是交換次數,找到幾個這樣的環然後計數,輸出結果即可。

#include<bits/stdc++.h>///任意兩數交換,那就找迴圈節,因為數都是唯一的,那麼找到每一個數應該在的位置,任何不在自己位置的數都是要交換的環中的,直接暴力找,計數即可
#define LL long long
#define M(a,b) memset(a,b,sizeof a)
#define pb(x) push_back
using namespace std;
const int maxn=1e5+7;
int a[maxn];
bool vis[maxn];
int main()
{
    int t,n;
    scanf("%d",&t);
while(t--) { M(vis,false); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); LL ans=0; for(int i=1;i<=n;i++) { int cnt=0; int tmp=i; while(!vis[tmp]&&a[tmp]!=tmp)///找下一個自己該在的位置 { cnt++; vis[tmp]=true;///標記環中該值是否被遍歷過 tmp=a[tmp]; } if(cnt) ans+=cnt-1;///每個環的交換次數求和 } printf("%lld\n",ans); } }