天天看點

Parallel Sort(思維)

題目描述

As a master of parallel computing, schwer is recently considering about the method to achieve quick sorting on parallel computers. He needs your help!

Given a permutation ( p 1 , ⋯   , p n ) (p_1,\cdots,p_n) (p1​,⋯,pn​), you need to sort the permutation with minimum number of rounds. In a single round, one can take many pairs of integers ( x 1 , y 1 ) (x_1,y_1) (x1​,y1​), ⋯ \cdots ⋯, ( x k , y k ) (x_k,y_k) (xk​,yk​) as long as the values of x 1 x_1 x1​, y 1 y_1 y1​, ⋯ \cdots ⋯, x k , y k x_k,y_k xk​,yk​ are pairwise distinct. Then with the help of k k k CPUs, for each i ∈ [ 1 , k ] i\in [1,k] i∈[1,k], the value of p x i p_{x_i} pxi​​ and p y i p_{y_i} pyi​​ will be switched immediately. Note that a permutation ( p 1 , ⋯   , p n ) (p_1,\cdots,p_n) (p1​,⋯,pn​) is sorted if for every integer i ∈ [ 1 , n ] i\in [1,n] i∈[1,n], p i = i p_i=i pi​=i holds.

Take some examples. Assume that n = 4 n=4 n=4. For p = ( 1 , 2 , 3 , 4 ) p=(1,2,3,4) p=(1,2,3,4), the minimum number of round is 00 as it is already sorted. For p = ( 4 , 3 , 2 , 1 ) p=(4,3,2,1) p=(4,3,2,1), the answer is 1 1 1, as you can swap the indices ( 1 , 4 ) (1,4) (1,4) and ( 2 , 3 ) (2,3) (2,3) simultaneously.

輸入描述:

he first line of input contains a single integer n n n ( 1 ≤ n ≤ 1 0 5 ) (1\leq n\leq 10^5) (1≤n≤105), indicating the length of the permutation.

The second line contains n n n integers p 1 , . . . , p n ( 1 ≤ p i ≤ n ) p_1,...,p_n(1\leq p_i\leq n) p1​,...,pn​(1≤pi​≤n), the given permutation. It is guaranteed that these integers form a permutation, that is, for every integer i ∈ [ 1 , n ] i\in [1,n] i∈[1,n] there exists an unique integer j ∈ [ 1 , n ] j\in [1,n] j∈[1,n] such that p j = i p_j=i pj​=i.

輸出描述:

The first line of output should contain a single integer m m m, the minimum number of rounds to get the permutation sorted. Then print m m m line to show one possible solution.

The i i i-th of the next mm lines should describe the i i i-th round of your solution, beginning with a single integer k k k, and followed by 2 k 2k 2k integers x 1 , y 1 ⋯ x k , y k x_1,y_1 \cdots x_k,y_k x1​,y1​⋯xk​,yk​. The constraints that 1 ≤ x i , y i ≤ n 1\leq x_i,y_i\leq n 1≤xi​,yi​≤n and the 2 k 2k 2k integers are pairwise distinct must be held.

輸入

4
1 2 3 4
           

輸出

輸入

4
4 3 2 1
           

輸出

1
2 1 4 2 3
           

思路

最初想到是貪心,每次必定能使 n 2 \frac n2 2n​ 個數字排好序, l o g 2 n log_2n log2​n 輪下來,能把所有數排序。并且使用一個隊列來記錄未排序,并且未在這一輪中交換過的數字。但是 l o g 2 n log_2n log2​n 不是最少的回合數。

建構一張有向圖, n n n 個結點,每個結點有一條出邊和一條入邊,那麼這張圖就是由若幹個環組成。

  • 一進制環需要 0 0 0 回合消掉環。
  • 二進制環需要 1 1 1 回合消掉環。
  • 多元環可以用一回合分解為若幹個二進制環(奇環還會拆分出一個一進制環),再用一回合消掉所有拆出來的環。
  • 所有環之間獨立

是以,最多兩回合可以消掉所有環。

例如一個五元環:

Parallel Sort(思維)

首先交換 1 , 3 1,3 1,3,從五元環上拆分出一個二進制環:

Parallel Sort(思維)

五元環變為了三元環,并且 3 3 3 在這一輪中不能再次交換。那交換 5 , 4 5,4 5,4,又拆分出一個二進制環。

Parallel Sort(思維)

下一輪可以消掉所有的環。

代碼中, dfs \text{dfs} dfs 中的 fst \text{fst} fst 參數為 0 0 0 代表這是第一次進入 dfs \text{dfs} dfs ,環上所有點都未交換過。 fst \text{fst} fst 為 1 1 1 代表拆分後的環上有一個點已經交換過,在這一輪中不能再次交換。

fst \text{fst} fst 參數隻有在環為二進制環的時候才有用。因為對于一個二進制環,若所有點都未交換過,那麼應該在第一輪中就解開這個環;若換上有一個點已經交換過,那這個二進制環需要在第二輪中解開。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int a[N],p[N],vis[N];
vector<int> op[2];

void swp(int i, int j,int t){
	op[t].push_back(i);
	op[t].push_back(j);
	swap(a[i],a[j]);
	p[a[i]] = i;  p[a[j]] = j;
	vis[i]=vis[j]=1;
}

void dfs(int i,int fst){
	if(a[i]==i) return;
	if(a[a[i]]==i) return swp(i,a[i],fst);
	int x=a[i],y=a[x],pre=p[i];
	swp(i,y,0); swp(y,x,1); dfs(pre,1);
}

int main(){
	int n;  cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],p[a[i]] = i;
	for(int i=1;i<=n;i++) if(!vis[i]&&a[i]!=i) dfs(i,0);
	int ans=(op[0].size()>0)+(op[1].size()>0);
	cout<<ans<<"\n";
	for(int i=0;i<ans;i++){
		cout<<op[i].size()/2;
		for(int j=0;j<(int)op[i].size();j++)
			cout<<" "<<op[i][j];
		cout<<"\n";
	}
}
           

繼續閱讀