UVA-11600-Masud Rana

来源:互联网 发布:苹果下软件赚钱的软件 编辑:程序博客网 时间:2024/05/21 10:09

ACM模版

描述

描述
描述

题解

很神的一个期望状压树型 DP

第一步:进行缩点,因为有的点本身就是联通的,所以缩成一个点 x,并用 cnt[x] 表示这个缩点所拥有的城市个数;

第二步:设 dp[u][st] 表示目前在 u 点的一个城市经过了 st 状态的缩点,还需要多少天才能消灭妖怪使满足道路通畅,因为这里 1N30,比较大,直接开数组没法开,并且没法使用滚动数组, 所以使用 map 存储。

现在来分析一下状态转移关系,设 n 为当前经过了 st 状态的城市个数,那么先考虑搞定这 n 个点所需要的时间,平均需要走 N1Nn 次才能搞定这些城市;当然此时还没有考虑完毕,还有树型部分的情况,那就是没有访问过的节点,走到节点 i 的概率为 cnt[i]Nn,若走到 i 节点,还平均需要 dp[i][st | (1<<i)],则

dp[u][st]=N1Nn+st & (1 << i) == 0cnt[i]Nndp[i][st | (1<<i)]

这个状态转移部分着实不好想,期望很玄……头疼。

描述

保存六位小数……

代码

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <map>#define INF 0x3f3f3f3f#define MAXN 32#define MAXM 500using 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;}
原创粉丝点击