2019 ICPC Greater New York Region C - PassTheBuck(概率)

题目链接


题目大意

n个人开始传球,每次要么把球传递给相邻的人,要么自己保留(保留就会赢得游戏),现在需要求给定传球的起点,问终点的人获胜的概率

解题思路

第一次做概率题就被这种无限传递的情况给吓住了,但是看了看题解,实际上就是当某轮的概率小于 1 e − 8 1e^{-8} 1e8时直接结束游戏即可。设置两个数组,一个表示当前轮每人得到球的概率,另一个表示下一轮每个人得到球的概率,然后第一个数组每轮结束后更新为第二个数组,再清空第二个数组开始下一轮游戏即可

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define lowbit(x) (x&(-x))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const ll INF=1e18;
const int Mod=1e9+7;
const int maxn=2e5+10;

bool G[50][50]={ 0 };
int degree[50]={ 0 };
int n,m,num;

double solve(int u,int v){
    double ans=0.0,roud=0.0,cur[25],nxt[25];
    for(int i=0;i<21;i++) cur[i]=nxt[i]=0.0;
    cur[u]=1.0;  //初始只有起点的人有球,概率为1
    while(roud==0.0 || roud>eps){  //第一次roud为0,后面不会为0,这里相当于特判
        ans+=roud;
        roud=0.0;
        for(int i=0;i<=n;i++) nxt[i]=0.0;
        for(int i=1;i<=n;i++){
            if(cur[i]>0.0){
                for(int j=1;j<=n;j++)
                    if(G[i][j]){  //能传递就传
                        if(i==j){ //终点的人传给本身才更新答案,其他人不能传给自己不然会导致游戏结束
                            if(i==v) roud+=cur[i]/(double)degree[i];
                        }else nxt[j]+=cur[i]/(double)degree[i];
                    }
            }
        }
        for(int i=0;i<21;i++) cur[i]=nxt[i];  //更新此轮每人得到球的概率
    }
    return ans;
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    //ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int x,kase,u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&num);
        degree[i]=num+1;
        while(num--){
            scanf("%d",&x);
            G[i][x]=G[x][i]=1;
        }
        G[i][i]=1;
    }
    while(m--){
        scanf("%d%d%d",&kase,&u,&v);
        //cout<<solve(u,v)<<endl;
        printf("%d %.5f\n",kase,solve(u,v));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值