重新排列奶牛

重新排列奶牛

农夫约翰的 $N$ 头奶牛排成一排,编号 $1 \sim N$。

它们的排序可以由一个数组 $A$ 来描述,其中 $A \left( i \right)$ 是位于位置 $i$ 的奶牛的编号。

约翰希望将它们重新排列为一个不同的顺序。

新顺序用数组 $B$ 来描述,其中 $B \left( i \right)$ 是位于位置 $i$ 的奶牛的编号。

假设奶牛开始时的顺序为:

A = 5 1 4 2 3

并假设约翰希望它们重新排列为:

B = 2 5 3 1 4

为了从 $A$ 顺序重新排列为 $B$ 顺序,奶牛们进行了许多“循环”移位。

所谓循环移位,是指挑选排列中的若干头奶牛分在一组,组中奶牛进行循环移动位置,即第一头奶牛移动至第二头奶牛的位置,第二头奶牛移动至第三头奶牛的位置,…,最后一头奶牛移动至第一头奶牛的位置。

如上例中,将 $5,1,2$ 号奶牛分在一组进行循环移位,移动过后,$5$ 号奶牛移动至位置 $2$,$1$ 号奶牛移动至位置 $4$,$2$ 号奶牛移动至位置 $1$;将 $4,3$ 号奶牛分在另一组进行循环移位,移动过后,$4$ 号奶牛位于位置 $5$,$3$ 号奶牛位于位置 $3$;最终完成重新排列。

每头奶牛都恰好参与一组循环移位,除非其在 $A,B$ 中的位置没有变化。

请计算奶牛们完成重新排列,共需多少组循环移位,最长的一组循环移位的长度是多少。

输入格式

第一行包含整数 $N$。

接下来 $N$ 行包含 $A \left( i \right)$。

再接下来 $N$ 行包含 $B \left( i \right)$。

输出格式

输出循环移位的组数,以及最长的一组循环移位的长度。

如果不存在循环移位,则第二个数输出 $−1$。

数据范围

$1 \leq N \leq 100$,
$1 \leq A \left( i \right),B \left( i \right) \leq N$

输入样例:

5
5
1
4
2
3
2
5
3
1
4

输出样例:

2 3

 

解题思路

  如果第$i$个数$a \left[ i \right]$在序列$b$中的第$j$个位置,并且如果有$i \ne j$,那么我们就将$a \left[ i \right]$与$a \left[ j \right]$连一条有向边,方向从$a \left[ i \right]$到$a \left[ j \right]$,表示$a \left[ i \right]$要与$a \left[ j \right]$进行交换,这样$a \left[ i \right]$才能够在序列$b$中$j$的这个位置。

  以样例为例:

  因此问题就变成了经过上面的操作后,一共有几个环(环中结点的数量要大于$1$)。

  然后题目表述的不是很清楚,当时一直想不明白如果遇到$a = \left[ {1, 3, 2} \right],~ b = \left[ {3, 2, 1} \right]$这种情况应该怎么交换。按照我一开始的理解,所谓的循环交换是指按照环的顺序进行移位,因此对于序列$1~3~2$无论怎么移位,都只有$2~1~3,~3~2~1,~1~3~2$这$3$种情况,不可能会出现$3~2~1$。然而事实是,这里的循环移位是指,选择其中一头牛,然后放到其他牛的地方。然后再把刚才被换出的牛放到其他没被换过的牛的地方,以此类推,直到最后一头牛,就放到空的位置上(这个空的位置就是一开始进行交换的牛的那个位置)。

  以上面的例子为例,一开始先选择$3$号牛,把$3$放到第$1$个位置,置换出$1$号牛,然后再把$1$号牛放到第$3$个位置,置换出$2$号牛,最后把$2$号牛放到空的位置。

  根据这些环的性质,我们可以发现这是一个环图的模型。因为如果一个点要放到另外一个点上,那么这个点就跟另外一个点连一条边,这样的话每一个点有且只有一条出边,和有且只有一条入边。

  环图是指:

  1. 如果一个图是有向图,每个点有且只有一条出边,有且只有一条入边,那么这个图是环图。
  2. 如果一个图是无向图,每个点的的度数为$2$,那么这个图是环图。

  环图一定是由若干个环构成的。我们可以从任意一个结点出发,那么一定可以从这个点走到另外一个点,继续一直走下去,那么最后一定会走到起点。这是因为,再走的过程中,如果走不到起点就会一直走,由于我们点的数量是有限的,所以最终一定会走到之前走过的某一个点,如果这点不是起点,那么这个点的入度就为$2$了,与每个点只有$1$个入度产生矛盾,因此最终一定会走到起点。而且也不会走到其他的环上,一样会有入度为$2$的矛盾。

  这是一个有向图,但环与环之间是不相交的。要求环的数量,等价于求连通块的数量(一个图是有向图不等价于连通块,只有是环图才等价于连通块)。维护连通块就可以用并查集了。

  AC代码如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 110;
 6 
 7 int a[N], pos[N];
 8 int fa[N], cnt[N];
 9 
10 int find(int x) {
11     return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
12 }
13 
14 int main() {
15     int n;
16     scanf("%d", &n);
17     for (int i = 1; i <= n; i++) {
18         scanf("%d", a + i);
19     }
20     for (int i = 1; i <= n; i++) {
21         int val;
22         scanf("%d", &val);
23         pos[val] = i;   // pos[i]是把数字i映射到在数组b中的下标,这里存的是数字val在b中的位置
24     }
25     
26     for (int i = 1; i <= n; i++) {
27         fa[i] = i;
28         cnt[i] = 1;
29     }
30     
31     for (int i = 1; i <= n; i++) {
32         int x = a[i], y = a[pos[a[i]]];
33         if (find(x) != find(y)) {
34             cnt[find(x)] += cnt[find(y)];
35             fa[y] = find(x);
36         }
37     }
38     
39     int ret = 0, maxv = 0;
40     for (int i = 1; i <= n; i++) {
41         if (fa[i] == i && cnt[i] > 1) { // 只统计长度大于1的环
42             ret++;
43             maxv = max(maxv, cnt[i]);
44         }
45     }
46     printf("%d %d", ret, ret == 0 ? -1 : maxv);
47     
48     return 0;
49 }

 

参考资料

  AcWing 1921. 重新排列奶牛(春季每日一题2022):https://www.acwing.com/video/3835/

posted @ 2022-04-25 20:30  onlyblues  阅读(102)  评论(0编辑  收藏  举报
Web Analytics