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) (1n105), 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(1pin), 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,y1xk,yk. The constraints that 1 ≤ x i , y i ≤ n 1\leq x_i,y_i\leq n 1xi,yin and the 2 k 2k 2k integers are pairwise distinct must be held.

输入

4
1 2 3 4

输出

0

输入

4
4 3 2 1

输出

1
2 1 4 2 3

思路

最初想到是贪心,每次必定能使 n 2 \frac n2 2n 个数字排好序, l o g 2 n log_2n log2n 轮下来,能把所有数排序。并且使用一个队列来记录未排序,并且未在这一轮中交换过的数字。但是 l o g 2 n log_2n log2n 不是最少的回合数。

构建一张有向图, n n n 个结点,每个结点有一条出边和一条入边,那么这张图就是由若干个环组成。

  • 一元环需要 0 0 0 回合消掉环。
  • 二元环需要 1 1 1 回合消掉环。
  • 多元环可以用一回合分解为若干个二元环(奇环还会拆分出一个一元环),再用一回合消掉所有拆出来的环。
  • 所有环之间独立

所以,最多两回合可以消掉所有环。

例如一个五元环:

首先交换 1 , 3 1,3 1,3,从五元环上拆分出一个二元环:

五元环变为了三元环,并且 3 3 3 在这一轮中不能再次交换。那交换 5 , 4 5,4 5,4,又拆分出一个二元环。

下一轮可以消掉所有的环。

代码中, 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";
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_51864047

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值