把每一个瓶子看成一个点,从每个瓶子向他应该在的那个位置的瓶子连一条边
通过这个方式,我们就可以连出n条边
观察可以发现这些图有特点:
n个点 连成n条边
因为每个点会指向它应该在的位置的那个点,他所在位置的对应的点会指向他,所以每个点的出度和入度都为1
不会有以下情况
都会是一个一个环
最终希望完成的样子是一个升序的 ,把整个图都变成自环
对点进行操作,分两种情况:
1️⃣交换同一个环内的点
如图,交换1 和 3的位置,意味着改变点1和点2的出边,让点1的出边指向点2先前出边方向,点2指向点1 先前出边的方向
可以发现将一个环裂开成了两个环
2️⃣交换不同环中的点
可以发现合并了两个环
初始的时候我们假设有k个环,n个点,我们的目标是将所有的环拆解成自环,每次操作最多增加一个环,因此次数 >= n-k次,只要有一个环里面存在两个或以上的点,我们就必然可以把它分裂一下,变成两个环,所以必然存在一种方案,可以使我们恰好操作n-k次就可以把k个环分解成n个环
所以答案>=n-k 且可以取到n-k
cpp
#include <iostream>
using namespace std;
const int N = 1e4 + 10;
int n;
int b[N];
bool st[N];
int main() {
cin >> n;
for (int i = 1;i <= n;i++) {
cin >> b[i];
}
int cnt = 0;
for (int i = 1;i <= n;i++) {
if (!st[i]) {
cnt++;
for (int j = i;!st[j];j=b[j]) {
st[j] = true;
}
}
}
int res = n - cnt;
cout << res << endl;
return 0;
}