[CSU 1818 Crusher's Code Submit]记忆化递推

[CSU 1818 Crusher’s Code Submit]记忆化递推

分类:递推 数学

1. 题目链接

[CSU 1818 Crusher’s Code Submit]

2. 题意描述

有两种随机排序的算法伪代码。现在给你一个长度为 N 的序列,分别用两种算法进行升序排序。求两种算法的迭代的次数的数学期望,精确到小数点后6位。2N8

3. 解题思路

首先,因为题目给定的状态转移是单向的,也就是说只可能交换两个逆序的元素,不存在状态之间的来回转移。
然后,可以列出状态转移的一个方程。
s 表示当前的状态的编号. t表示目标状态的编号, dp[i] 就是从当前状态出发到目标状态的期望值。
那么,

  • 对于算法一:
    dp[s]=icnt[(dp[ti]+1)2n2]+[(dp[s]+1)n22cntn2]
  • 对于算法二:
    dp[s]=icnt[(dp[ti]+1)1n1]+[(dp[s]+1)n1cntn1]

然后,移项就可以得到状态转移方程了。

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值