[一本通1684]翻轉序列 題解
阿新 • • 發佈:2021-08-12
給定一個$1\sim n$的排列$x$,每次你可以將$x_1\sim x_i$翻轉。你需要求出將序列變為升序的最小操作次數。有多組資料。.......本題從求最小步數就可以知道,需要使用IDA。而我們最終是要求一個翻轉成遞增序列。
。
對於測試點\(10,n=9\)。
對於測試點\(11,n=10\)。
對於測試點\(i (12≤i≤21),n=i\)。
對於測試點\(22,23,n=22\)。
對於測試點\(24,25,n=23\)。
題目描述
給定一個\(1\sim n\)的排列\(x\),每次你可以將\(x_1\sim x_i\)翻轉。你需要求出將序列變為升序的最小操作次數。有多組資料。
輸入
第一行一個整數\(t\)表示資料組數。
每組資料第一行一個整數\(n\),第二行\(n\)個整數\(x_1\sim x_n\)。
輸出
每組資料輸出一行一個整數表示答案。
輸入樣例
1
8
8 6 1 3 2 4 5 7
輸出樣例
7
提示
資料規模與約定
對於100%的測試資料,\(t=5,n≤23\)。
對於測試點\(1,2,n=5\)。
對於測試點\(3,4,n=6\)。
對於測試點\(5,6,n=7\)。
對於測試點\(7,8,9,n=8\)
對於測試點\(10,n=9\)。
對於測試點\(11,n=10\)。
對於測試點\(i (12≤i≤21),n=i\)。
對於測試點\(22,23,n=22\)。
對於測試點\(24,25,n=23\)。
思路
本題從求最小步數就可以知道,需要使用IDA。而我們最終是要求一個翻轉成遞增序列。
先從最簡單粗暴的方法想起。
如果第1大的數大在第一位,只需要翻轉一次就可以歸位。如果不在第一位,先翻轉到第一位,兩次翻轉也能歸位。這樣我們就可以推出IDA函式
程式碼
#include <iostream> #include <cmath> #include <algorithm> using namespace std; const int N = 24; int num[N]; int n; inline int IDA() { int cnt = 0; for (int i = 1; i < n; i++) if (abs(num[i] - num[i + 1]) > 1) cnt++; return cnt; } bool ac = false; int ans = 1e9; void dfs(int dep, int last) { if (ac) return; if (dep + IDA() > ans) return; bool tag = false; //完成標籤 for (int i = 1; i < n; i++) if (num[i] != num[i + 1] - 1) { tag = true; break; } if (!tag) //完成 { ac = true; return; } for (int i = 2; i <= n; i++) { if (i != last) { reverse(num + 1, num + 1 + i); dfs(dep + 1, i); reverse(num + 1, num + 1 + i); } } } int main() { int T; cin >> T; while (T--) { cin >> n; for (int i = 1; i <= n; i++) { cin >> num[i]; } for (ans = 0;; ans++) { ac = false; dfs(0, 0); if (ac) break; } cout << ans << endl; } }