CF612E Square Root of Permutation 題解 圖論建圖題
阿新 • • 發佈:2020-12-24
題目連結:http://codeforces.com/contest/612/problem/E
題目大意:給你一個 \(1\) 到 \(n\) 的排列,求一個 \(1\) 到 \(n\) 的排列 \(q\) 滿足 \(q_{q_i} = p_i\)。無解則輸出 \(-1\)。
解題思路(完全參照自 SovietPower大佬的部落格):
對排列 \(q_i\) 我們建一個圖,邊為 \(i \rightarrow q_i\)。顯然這張圖是有幾個環構成的。
對於 \(p_i\)(即 \(q_{q_i}\)),原來 \(q_i\) 中的奇環在 \(p_i\) 中也是由同樣的資料組成的奇環,只不過排列順序變成了 \(1,2,5,\ldots,n,2,4,\ldots,n-1\)
所以對 \(p_i\) 建圖,找出對應的環。奇環單獨處理,兩個大小相同的偶環一起處理。就能還原出 \(q_i\) 對應的圖了。
示例程式碼如下:
#include <bits/stdc++.h> using namespace std; const int maxn = 1000010; int n, p[maxn]; int sz[maxn], head[maxn], tmp[maxn], m, q[maxn]; bool vis[maxn]; bool cmp(int i, int j) { return sz[i] < sz[j]; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++) scanf("%d", p+i); for (int i = 1; i <= n; i ++) { if (!vis[i]) { head[m++] = i; int j = i; while (!vis[j]) { vis[j] = true; sz[i] ++; j = p[j]; } if (j != i) { puts("-1"); return 0; } } } sort(head, head+m, cmp); for (int i = 0; i < m; i ++) { int u1 = head[i], u2 = head[i+1]; if (sz[u1] % 2) { // 奇環 int x = u1, y = 0; for (int j = 0; j < sz[u1]; j ++) { tmp[y] = x; y = (y + 2) % sz[u1]; x = p[x]; } assert(x == u1); for (int j = 0; j < sz[u1]; j ++) q[ tmp[j] ] = tmp[(j+1) % sz[u1]]; } else { // 偶環 if (i == m-1 || sz[u1] != sz[u2]) { puts("-1"); return 0; } // 處理偶環 int x = u1, y = u2; for (int i = 0; i < sz[u1]; i ++) { q[x] = y; q[y] = p[x]; x = p[x]; y = p[y]; } i ++; // 多加上1 } } for (int i = 1; i <= n; i ++) printf("%d ", q[i]); return 0; }