踢足球

题意

2n 个人分成2 队玩足球。每队每个球员的队服上有一个1 到n 的正整数(同一个队内的数字不重复)。我们可以知道每个球员的精准度,他可以进行传球的队友集合F 和可以把他的球抢走的敌队球员集合E。当一个球员接到了球,在恰好一秒钟后会发生以下的事件:
1) 该球员把球传给F 集合中的随意一个队员。
2) E 集合中的随意一个敌队球员把球抢走。
3) 该球员射球。
如果该球员射球,他能得分的概率等于他的精准度。在射球之后,不管能否得分,球都会判给敌队的一号球员。发生以上三种不同事件的概率比是|F| : |E| : 1。概率比取决于当前接到球的球员(|S|代表S 集合的规模),而与之前发生的任何事件无关。“随意”的意思是所有在集合F(或E)的球员有相同的概率可以从目前带球的球员得到球(或抢走球)。球在球员之间转移的时间忽略不计。比赛从1 队的1 号球员带球开始,直到任意一队得到R 分或已经过了T 秒。对于任何可能的最终比分,计算出得出该比分的概率。

分析

我们只需要知道比分的情况,对于中间的比赛情况我们不需要知道。
我们设 f[i][t][A][B] i 队在t时开球,此时场上比分为 A:B 的概率 (i[0,1])
我们需要其他数组来辅助转移。
g[i][j][t] i 队开球t秒后j队得分的概率,那么 f[1j][t+x][A+1j][B+j]=f[i][t][A][B]g[i][j][x](x[1,Tt],j[0,1])
现在我们的问题变成如何求 g 数组了。
h[i][j][k][t] i 队开球过t秒后,球在 j k号球员脚下的概率。
g[i][j][t+1]=k=1nh[i][j][k][t]goal[j][k] ,其中 goal[j][k] j k号球员在一个时刻射门且射进的概率。
至于 h 的转移就比较简单了。
我们还要记录一个delay[i][t],表示 i 队开球后过了t秒仍然没有进球,用来计算一个状态若它到比赛结束都没有再进球,这个状态对答案的贡献。该数组可以用 h <script type="math/tex" id="MathJax-Element-48">h</script>数组转移。

#include <cstdio>
#include <cstring>
using namespace std;

const int N = 101,TT = 501;
int n,r,T;
int cnt[2][N];
double p[2][2][N][N],goal[2][N],delay[2][TT],ans[11][11],f[2][TT][11][11],g[2][2][TT],h[2][2][N][TT];

void init() {
    scanf("%d%d%d",&n,&r,&T);
    int r,nf,ne,x;
    for (int k = 0;k <= 1;++ k) {
        for (int i = 1;i <= n;++ i) {
            scanf("%lf",&goal[k][i]);
            scanf("%d%d",&nf,&ne);
            cnt[k][i] = nf + ne + 1;
            for (int S = 0;S <= 1;++ S) {
                if (S == 0) r = nf;else r = ne;
                for (int j = 1;j <= r;++ j) {
                    scanf("%d",&x);
                    p[k][S ^ k][i][x] = 1 / float(cnt[k][i]);
                }
            }
            p[k][k ^ 1][i][1] += (1 - goal[k][i]) / cnt[k][i];
            goal[k][i] /= cnt[k][i];
        }
    }
}

void work() {
    h[0][0][1][0] = h[1][1][1][0] = 1;
    for (int t = 0;t < T;++ t) {
        for (int i = 0;i <= 1;++ i) {
            for (int j = 0;j <= 1;++ j) {
                for (int k = 1;k <= n;++ k) if (h[i][j][k][t]) {
                    delay[i][t]+=h[i][j][k][t];
                    g[i][j][t + 1] += h[i][j][k][t] * goal[j][k];
                    for (int j1 = 0;j1 <= 1;++ j1) {
                        for (int k1 = 1;k1 <= n;++ k1) 
                            h[i][j1][k1][t + 1] += h[i][j][k][t] * p[j][j1][k][k1];
                    }
                }
            }
        }
    }
    for (int i = 0;i <= 1;++ i) 
        for (int j = 0;j <= 1;++ j) 
            for (int k = 1;k <= n;++ k) 
                delay[i][T]+=h[i][j][k][T];
    delay[0][0] = delay[1][0] = 1;
}

void solve() {
    f[0][0][0][0] = 1;
    for (int t = 0;t < T;++ t) {
        for (int i = 0;i <= 1;++ i) {
            for (int a = 0;a < r;++ a) {
                for (int b = 0;b < r;++ b) if (f[i][t][a][b]){
                    ans[a][b] += f[i][t][a][b] * delay[i][T - t];
                    for (int x = 1;x <= T - t;++ x) {
                        for (int j = 0;j <= 1;++ j) {
                            f[1 ^ j][t + x][a + 1 - j][b + j] += f[i][t][a][b] * g[i][j][x];
                        }
                    }
                }
            }
        }
    }
    for (int t = 0;t < T;++ t) {
        for (int i = 0;i <= 1;++ i) {
            for (int j = 0;j < r;++ j) {
                ans[j][r] += f[i][t][j][r];
                ans[r][j] += f[i][t][r][j];
            }
        }
    }
}

int main() {
    init();
    work();
    solve();
    for (int i = 0;i <= r;++ i) {
        for (int j = 0;j <= r;++ j) {
            if (i == r && j == r) break;
            printf("%.7lf\n",ans[i][j] + f[0][T][i][j] + f[1][T][i][j]);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值