[CSU 1818 Crusher’s Code Submit]记忆化递推
分类:递推
数学
1. 题目链接
[CSU 1818 Crusher’s Code Submit]
2. 题意描述
有两种随机排序的算法伪代码。现在给你一个长度为
N
的序列,分别用两种算法进行升序排序。求两种算法的迭代的次数的数学期望,精确到小数点后6位。
3. 解题思路
首先,因为题目给定的状态转移是单向的,也就是说只可能交换两个逆序的元素,不存在状态之间的来回转移。
然后,可以列出状态转移的一个方程。
用
s
表示当前的状态的编号.
那么,
- 对于算法一:
dp[s]=∑状态i总状态数cnt[(dp[ti]+1)∗2n2]+[(dp[s]+1)∗n2−2∗cntn2] - 对于算法二:
dp[s]=∑状态i总状态数cnt[(dp[ti]+1)∗1n−1]+[(dp[s]+1)∗n−1−cntn−1]
然后,移项就可以得到状态转移方程了。
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-6;
const int MAXN = 1e3 + 5;
int T, N;
unordered_map<int, LB> dp[2];
unordered_map<int, bool> vis[2];
int dst;
int Hash(const vector<int>& x) {
int ret = 0;
for(int i = 0; i < N; ++i) {
ret = ret * 8 + x[i];
}
return ret;
}
LB dfs1(vector<int>& x) {
int v = Hash(x);
if(v == dst) return 0;
if(vis[0][v]) return dp[0][v];
dp[0][v] = 0;
int cnt = 0;
for(int i = 0; i < N; ++i) {
for(int j = i + 1; j < N; ++j) {
if(x[i] <= x[j]) continue;
cnt ++;
swap(x[i], x[j]);
dp[0][v] += (dfs1(x) + 1) * 2;
swap(x[i], x[j]);
}
}
dp[0][v] += N * N - 2 * cnt;
dp[0][v] /= 2 * cnt;
vis[0][v] = true;
return dp[0][v];
}
LB dfs2(vector<int>& x) {
int v = Hash(x);
if(v == dst) return 0;
if(vis[1][v]) return dp[1][v];
dp[1][v] = 0;
int cnt = 0;
for(int i = 0; i < N - 1; ++i) {
int j = i + 1;
if(x[i] <= x[j]) continue;
cnt ++;
swap(x[i], x[j]);
dp[1][v] += (dfs2(x) + 1);
swap(x[i], x[j]);
}
dp[1][v] += (N - 1 - cnt);
dp[1][v] /= cnt;
vis[1][v] = true;
return dp[1][v];
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
scanf("%d", &T);
while(T --) {
dp[0].clear(), dp[1].clear();
vis[0].clear(), vis[1].clear();
scanf("%d", &N);
vector<int> a(N), f(N), b(N);
for(int i = 0; i < N; ++i) scanf("%d", &a[i]), f[i] = a[i];
sort(f.begin(), f.end()); f.erase(unique(f.begin(), f.end()), f.end());
for(int i = 0; i < N; ++i) b[i] = a[i] = lower_bound(f.begin(), f.end(), a[i]) - f.begin();
sort(b.begin(), b.end());
dst = Hash(b);
int v = Hash(a);
dfs1(a), dfs2(a);
printf("Monty %.6f Carlos %.6f\n", (double)dp[0][v], (double)dp[1][v]);
}
return 0;
}