首页 > 其他 > 详细

概率期望训练之三

时间:2019-10-27 22:56:45      阅读:83      评论:0      收藏:0      [点我收藏+]

http://acm.hdu.edu.cn/showproblem.php?pid=5036

题目大意:

开始你没有任何钥匙,而你面前有很多道门,每道门后面可能有打开其他门的钥匙,如果你无法打开这道门,可以选择将它炸开,求打开所有门的期望炸的次数

分析:

首先根据期望的线性性

炸开所有门的期望次数=Σ每道门的期望次数

但这道题烦就烦在有可能会有环

先建图

假如没有环的话,ans=Σ1/dep[i]

但现在有环怎么办?

你肯定和我想的一样,Tarjan缩点呗

然后就莫名其妙的wa了(应该是我写错了,正解只是更简化了)

wa code:(不想看就跳过)

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define ri register int
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=1e3+5;
bool vis[maxn];
queue<int>S;
vector<int>Q[maxn],t[maxn];
double ans;
int T,cnt,top,sum,n,ca;
int dfn[maxn],deg[maxn],sz[maxn],belong[maxn],low[maxn],stk[maxn],dep[maxn];
il void Tarjan(int u){
    dfn[u]=low[u]=++cnt;vis[u]=true;
    stk[++top]=u;
    for(ri i=0;i<Q[u].size();i++){
        int to=Q[u][i];
        if(!dfn[to])Tarjan(to),low[u]=min(low[to],low[u]);
        else if(vis[u])low[u]=min(dfn[to],low[u]);
    }
    if(dfn[u]==low[u]){
        ++sum;sz[sum]=0;t[sum].clear();int tp;
        do{
            tp=stk[top--];
            vis[tp]=false;
            belong[tp]=sum;
            sz[sum]++;
        }while(tp!=u);
}}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(ri i=1;i<=n;i++){deg[i]=dfn[i]=low[i]=dep[i]=0;
            int tot;scanf("%d",&tot);
            Q[i].clear();
            for(ri j=1;j<=tot;j++){
            int x;scanf("%d",&x);
            if(x==i)continue;
            Q[i].push_back(x);
            }
        }
        cnt=top=sum=ans=0;
        for(ri i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
        for(ri u=1;u<=n;u++)
            for(ri i=0;i<Q[u].size();i++){
                int to=Q[u][i];
                if(belong[to]!=belong[u])t[belong[u]].push_back(belong[to]),deg[belong[to]]++;
            }
            for(ri i=1;i<=sum;i++)if(!deg[i]){S.push(i),dep[i]=sz[i];}
            while(!S.empty()){
                int tmp=S.front();S.pop();
                ans+=(double)sz[tmp]/dep[tmp];
            for(ri i=0;i<Q[tmp].size();i++){
                int to=Q[tmp][i];
                deg[to]--;dep[to]+=dep[tmp];
                if(!deg[to]){
                    dep[to]+=sz[to];
                    S.push(to);
                }
            }   
            }
        printf("Case #%d: %.05f\n", ++ca, ans);
    }
    return 0;
}
/*
2
3
1 2
1 3
1 1
3
0
0
0
*/

正解

考虑传递闭包:

所谓传递闭包就是A能够到B,B能够到C,那么A也就能够到C

考虑集合S能够到A,集合T能够到B,A能够到B,则A|S|T就能够到B

bitset维护即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
const int maxn = 1e3 + 5;
bitset<maxn> v[maxn];
int main()
{
    int t, ca = 1, n, k, x;
    cin >> t;
    while(t--)
    {
        scanf("%d", &n);
        for (int i = 0; i <= n; i++)
            v[i].reset(),v[i][i] = true;//它自己也要算上 
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &k);
            for(int j = 1; j <= k; j++)
                scanf("%d", &x),v[i][x] = 1;
        }
        for(int i = 1; i <= n; i++)  
            for(int j = 1; j <= n; j++)
                if(v[j][i])
                    v[j] |= v[i];//传递闭包 
        double ans = 0;
        for(int i = 1; i <= n; i++)
        {
            int cnt = 0;
            for(int j = 1; j <= n; j++)
                if(v[j][i]) cnt++;
            ans += 1.0 / cnt;
        }
        printf("Case #%d: %.05f\n", ca++, ans);
    }
    return 0;
}

概率期望训练之三

原文:https://www.cnblogs.com/wzxbeliever/p/11748999.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!