妙妙趣排序
題目
本題中:
一個即將排好序的序列定義爲:將這個序列去除至多一個值後,新序列是嚴格遞增的。
一個過濾器[u,v]定義爲:一個序列a經過過濾器[u,v]後,,其他值不變。
妙妙趣排序器由k個過濾器組成,一個序列的妙妙趣排序需要依次經過排序器的k個過濾器。
那麼請問,1~n的全排列中,有幾個序列經過給定的妙妙趣排序後可以變成即將排好序的序列。
輸入
第一行一個正整數t表示數據組數
接下來 t 組數據
每組數據第一行兩個整數
每組數據接下來k行,每行兩個整數,表示一個過濾器
輸出
每組數據輸出一行,一個整數
輸入樣例
4
4 0
4 1
1 2
4 3
1 2
2 3
1 2
4 6
1 2
2 3
1 2
3 4
2 3
1 2
輸出樣例
10
14
24
24
思路
首先考慮一點,任意一個排列,如果排序後可以變成即將排好序的序列,那麼他一定對應一個且僅一個即將排好序的序列。多個排列可能對應一個即將排好序的序列。也就是說,這是一個類似於函數多對一的關係。
那麼,我們來枚舉所有即將排好序的序列,反推其原始排列,這些原始排列一定不會重複。
所以,枚舉+dfs即可。注意dfs過程中剪枝驗證合法性、
枚舉所有即將排好序的序列可以在 內完成,dfs的複雜度大概爲
代碼
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const int ms = 50 + 10;
const int inf = 0x3f3f3f3f;
int t, n, k;
pair<int, int> opt[ms];
int ans;
void dfs(int x, vector<int>& to)
{
if (x == 0)
{
ans++;
return;
}
int u = opt[x].first - 1, v = opt[x].second - 1;
if (to[u] > to[v])return;
dfs(x - 1, to);
swap(to[u], to[v]);
dfs(x - 1, to);
swap(to[u], to[v]);
}
int main()
{
cin >> t;
while (t--)
{
ans = 0;
scanf("%d%d", &n, &k);
for (int i = 1; i <= k; ++i)
{
scanf("%d%d", &opt[i].first, &opt[i].second);
}
vector<int> to(n, 0);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
to[j] = j + 1;
}
for (int j = i; j > 0; --j)
{
swap(to[j], to[j - 1]);
if (i >= 1 && j == i) continue;
dfs(k, to);
}
for (int j = 0; j < i; ++j)
{
swap(to[j], to[j + 1]);
}
for (int j = i; j < n - 1; ++j)
{
swap(to[j], to[j + 1]);
dfs(k, to);
}
}
for (int j = 0; j < n; ++j)
{
to[j] = j + 1;
}
dfs(k, to);
printf("%d\n", ans);
}
return 0;
}