UVA 11600 Masud Rana(概率dp)

当两个城市之间有安全的道路的时候,他们是互相可到达的,这种关系满足自反、对称和传递性,

因此是一个等价关系,在图论中就对应一个连通块。

在一个连通块中,当前点是那个并不影响往其他连通块的点连边,因此只要记录当前连通块内有哪些点。

n<=30,数组是开不下的,而且状态转移是很少的,只会向二进制1数量增加的方向转移,所以用map保存。(最极限的应该是是2^29...)

适合用记忆化搜索来写。

很容易想到的转移方程是

S表示当前所在连通块,p是向连通快内点走的概率,trans走向某个点的概率,newS表示走到当前连通块以外得到的新连通块。

如果直接用这个式子计算会无限递归的,做一点小小的变形就好了

这样dp(S)的计算就不依赖dp(S)本身了。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 30;

int n,m;

int pa[maxn];
int wei[maxn];
int fdst(int x) { return x == pa[x]? x : pa[x] = fdst(pa[x]); }
void mrge(int x,int y)
{
    int a = fdst(x), b = fdst(y);
    if(a != b){
        pa[a] = b;
        wei[b] |= wei[a];
    }
}
void initUF()
{
    for(int i = 0; i < n; i++){
        pa[i] = i;
        wei[i] = 1<<i;
    }
}

map<int,double> meo;
map<int,double>:: iterator it;
#define MP make_pair
#define fi first
#define se second
double tr;

double dp(int s)
{
    if((it = meo.find(s)) != meo.end()) return it->second;
    double ans = 0;
    int lks = 0;
    for(int i = n; i--;){
        if(s>>i&1) { lks++; continue; }
        ans += dp(s|wei[i]);
    }
    ans = (n-1.)/(n-lks)*(tr*ans + 1);
    meo.insert(MP(s,ans));
    return ans;
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    int T, ks = 0; cin>>T;
    while(T--){
        scanf("%d%d",&n,&m);
        printf("Case %d: ",++ks);
        if(n == 1){
            puts("0");
            continue;
        }
        initUF();
        for(int i = m; i--; ){
            int x,y; scanf("%d%d",&x,&y);
            mrge(x-1,y-1);
        }
        tr = 1./(n-1);
        for(int i = n; i--;){
            wei[i] = wei[fdst(i)];
        }
        meo.clear();
        meo.insert(MP((1<<n)-1,0));
        printf("%lf\n",dp(wei[0]));
    }
    return 0;
}
时间: 2024-10-13 10:01:35

UVA 11600 Masud Rana(概率dp)的相关文章

UVA 11600 Masud Rana 并查集+状压概率dp

题目链接:点击打开链接 题意:给定一个无向图,给定的边是已经存在的边,每天会任选两个点新建一条边(建过的边还会重建) 问:使得图连通的天数的期望. 思路:状压喽,看别人都是这么写的,n=30,m=0 我也不知道怎么办了.. 当前连通块点数为X 加入一个Y个点的连通块需要的天数为 Y/(n-X); Masud Rana, A Daring Spy Of Bangladesh Counter Intelligence. He is in a new mission. There is a total

UVA 10529 Dumb Bones 概率dp 求期望

题目链接:点击打开链接 题意: 要在一条直线上摆多米诺骨牌. 输入n, l, r 要摆n张排,每次摆下去向左倒的概率是l, 向右倒的概率是r 可以采取最优策略,即可以中间放一段,然后左右两边放一段等,摆放顺序任意. 问:在最佳策略下要摆成n张牌的期望次数. 思路: 点击打开链接 #include <cstdio> #include <iostream> #include <cstring> #include <queue> #include <algo

UVA 10529 - Dumb Bones (概率dp)

题目描述 You are trying to set up a straight line of dominos, standing on end, to be pushed over later for your entertainment. (Sure, it seems pointless to set something up only to knock it down again, but you have some strange hobbies) The tricky thing

UVA 10529-Dumb Bones(概率dp)

题意: 给出放一个多米诺骨牌,向左向右倒的概率,求要放好n个骨牌,需要放置的骨牌的期望次数. 分析: 用到区间dp的思想,如果一个位置的左面右面骨牌都已放好,考虑,放中间的情况, dp[i]表示放好前i个骨牌,要放的期望次数,枚举1-i,每个点做中间点求对应的期望,取最小值. dp[i]=min(L*dp[l]+R*dp[r]+1/(1.0-L-R)); #include <map> #include <set> #include <list> #include <

UVA 1637 Double Patience 概率DP

Double Patience Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Double Patience is a single player game played with a standard 36-card deck. The cards are shuffled and laid down on a table in 9 pile

UVa 11468 (AC自动机 概率DP) Substring

将K个模板串构成一个AC自动机,那些能匹配到的单词节点都称之为禁止节点. 然后问题就变成了在Tire树上走L步且不经过禁止节点的概率. 根据全概率公式用记忆化搜索求解. 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 6 const int maxnode = 500; 7 const int sigma_size = 64; 8 int idx[2

uva 12723 概率dp

Dudu is a very starving possum. He currently stands in the first shelf of a fridge. This fridge iscomposed of N shelves, and each shelf has a number Qi (1 ≤ i ≤ N) of food. The top shelf, whereDudu is, is identified by the number 1, and the lowest is

UVa 10828 Back to Kernighan-Ritchie 高斯消元+概率DP

题目来源:UVa 10828 Back to Kernighan-Ritchie 题意:从1开始 每次等概率从一个点到和他相邻的点 有向 走到不能走停止 求停止时每个点的期望 思路:写出方程消元 方程有唯一解 多解 无解的情况 有环 一直再环里无法停止算无穷大 从1不能到的点期望为0 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <

uva 10529 - Dumb Bones(概率+区间dp)

题目连接:uva 10529 - Dumb Bones 题目大意:给定n,表示要放n个骨牌,每次放下骨牌,有可能向左倒的概率为pl,向右倒的概率为pr,如果倒下,会将那一侧的骨牌全部推倒,可以选择位置先后放骨牌,问说一种放骨牌次数最少的期望是多少. 解题思路:dp[i]表示放i个骨牌需要的步数期望,维护一个最优放的位置,dp[i] = min\{ (从i-1到i的步数)} + (0到i-1的步数)} (从i-1到i的步数):dp[i?j?1]?pl+dp[j]?pr+11?pl?pr (0到i-