描述
 
 
题解
很神的一个期望状压树型 DP 。
第一步:进行缩点,因为有的点本身就是联通的,所以缩成一个点  x ,并用    
第二步:设  dp[u][st]  表示目前在  u  点的一个城市经过了    
现在来分析一下状态转移关系,设  n  为当前经过了    
    dp[u][st]=N−1N−n+∑st & (1 << i) == 0cnt[i]N−n∗dp[i][st | (1<<i)]   
     这个状态转移部分着实不好想,期望很玄……头疼。
保存六位小数……
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#define INF 0x3f3f3f3f
#define MAXN 32
#define MAXM 500
using namespace std;
int T, N, M, tot;
int vis[MAXN];
int cnt[MAXN];
int mp_[MAXN][MAXN];
map<int, double> dp[MAXM];
void dfs(int x)
{
    vis[x] = 1;
    cnt[tot]++;
    for (int i = 1; i <= N; i++)
    {
        if (mp_[x][i] && !vis[i])
        {
            dfs(i);
        }
    }
}
int num(int x)
{
    int ret = 0;
    for (int i = 0; i < tot; i++)
    {
        if (x & (1 << i))
        {
            ret += cnt[i];
        }
    }
    return ret;
}
double get_dp(int u, int st)
{
    if (dp[u].count(st))
    {
        return dp[u][st];
    }
    double &ans = dp[u][st];
    int n = num(st);
    if (n == N)
    {
        return ans = 0;
    }
    ans = 1.0 * (N - 1) / (N - n);
    for (int i = 0; i < tot; i++)
    {
        if (!(st & (1 << i)))
        {
            ans += get_dp(i, st | (1 << i)) * cnt[i] / (N - n);
        }
    }
    return ans;
}
int main()
{
    scanf("%d", &T);
    for (int ce = 1; ce <= T; ce++)
    {
        scanf("%d%d", &N, &M);
        memset(mp_, 0, sizeof(mp_));
        memset(vis, 0, sizeof(vis));
        memset(cnt, 0, sizeof(cnt));
        int u, v;
        while (M--)
        {
            scanf("%d%d", &u, &v);
            mp_[u][v] = mp_[v][u] = 1;
        }
        // 缩点
        tot = 0;
        for (int i = 1; i <= N; i++)
        {
            if (!vis[i])
            {
                dfs(i);
                tot++;
            }
        }
        for (int i = 0; i < N; i++)
        {
            dp[i].clear();
        }
        printf("Case %d: %.6lf\n", ce, get_dp(0, 1));
    }
    return 0;
}
京公网安备 11010502036488号