【题解】闯关游戏

题目描述

  艾伦正在闯关。游戏有N个关卡,按照必须完成的顺序编号为1到N。每个关卡可以用两个参数来描述:prob [i]和value [i]。这些参数的含义如下:

  每当艾伦尝试闯第i关时,他要么顺利通过,要么“挂掉”。他完成该关卡的概率总是prob [i] / 1000。(他总是尽力完成每个关卡。)在关卡i的末尾有一个宝箱,其中包含价值 value[i]单位的黄金。当艾伦完成关卡时,他从拿起该关卡的金币。

  初始化时,艾伦从第1级关卡开始,艾伦没有黄金。对于每个有效的i,每当Allen完成关卡i时,他就会继续进行关卡i + 1,一旦完成第N个关卡,游戏就会结束。

  每当艾伦“挂掉”时,下面4件事情会按顺序发生:

        1、除了艾伦携带的黄金,其他黄金都被从游戏中移除。

        2、艾伦目前所携带的所有黄金都“坠落”,“坠落”的地点就是艾伦“挂掉”的那个关卡的开头处。一旦艾伦以后再次达到这个关卡,即使在尝试闯该关卡之前,他也能够再次“捡起”上次“坠落”到这个地方的黄金。(请注意,如果他在到达这个关卡之前再次“挂掉”,这些黄金将永远消失。)

        3、所有箱子都添加了新的黄金,各个箱子黄金的量就是它们最初所含的量(相当于初始化各个箱子的黄金量)。

        4、艾伦回到了第1级的开头,且他没有携带金币。艾伦有无限条“生命”,“挂掉”后可以重新开始游戏。

  通过上面的规则可以发现,艾伦“挂掉”后,最多只有一堆金币不在宝箱中,这一堆金币的位置就是艾伦最近“挂掉”所在的关卡的开头处。

  为了避免精确错误,数据保证艾伦在一次性闯关全部成功的情况下赢得整个游戏的概率将至少为10 ^( - 6)。你的任务是输出艾伦顺利闯完第N关时所携带的黄金的期望值。

 

输入格式

  多组测试数据。

  第一行,一个整数G,表示有G组测试数据。1 <= G <= 5。

  每组数据格式:

       第一行,一个整数N。2 <= N <= 1000。

       第二行,N个整数,第i个整数是prob[i]。1 <= prob[i] <= 1000。

       第三行, N个整数,第i个整数是value[i]。1 <= value[i] <= 1000。

 

输出格式

  共G行,每行一个实数。答案误差不能超过0.00001.

 

输入样例

5

2

1000 500 

3 4 

2

1000 1 

3 4 

5

500 500 500 500 500 

1 2 3 4 5 

91

916 932 927 988 958 996 944 968 917 939 960 965 960 998 920 990 915 972 995 916 902 968 970 962 922 959 994 915 996 996 994 986 945 947 912 946 972 951 973 965 921 910 938 975 942 950 900 983 960 998 982 980 902 974 952 938 900 962 920 931 964 974 953 995 946 946 903 921 923 985 919 996 930 915 991 967 996 911 999 936 1000 962 970 929 966 960 930 920 958 926 983 

583 428 396 17 163 815 31 536 175 165 532 781 29 963 331 987 599 497 380 180 780 25 931 607 784 613 468 140 488 604 401 912 204 785 697 173 451 849 714 914 650 652 338 336 177 147 22 652 901 548 370 9 118 487 779 567 818 440 10 868 316 666 690 714 623 269 501 649 324 773 173 54 391 745 504 578 81 627 319 301 16 899 658 586 604 83 520 81 181 943 157 

2

250 750 

1000 1 

 

输出样例

10.0

3003.9999999999977

16.626830517153095

54204.93356505282

1067.6666666666667

 

题解

  容易想到,当玩家在第$i$关挂掉时,如果他再次挂掉的关卡$j$满足$j<i$,那么他在第$i$关掉落的金币就消失了。

  这样我们可以看出,设$dp[i]$为第$i+1$关挂掉的期望值,那么能对$dp[i]$做出贡献的只有满足$j<i$的$dp[j]$。

  我们设$f[i]$为第$i+1$关挂掉的概率,容易得到$f[i]=\prod_{j=1}^{i}p[j] \times (1-p[i+1])$, 则$dp[i] = \sum_{j = 1}^{i} a[j] + \sum_{j = 1}^{i} f[j] \times dp[j]$,整理得到$dp[i] = \frac{\sum_{j = 1}^{i} a[j] + \sum_{j = 1}^{i - 1} f[j] \times dp[j]}{1 - f[i]}$。

#include <iostream>
#include <cstdio>

#define MAX_N (1000 + 5)

using namespace std;

int G;
int n;
double p[MAX_N];
double f[MAX_N];
double a[MAX_N];
double dp[MAX_N];
double s[MAX_N];

int main()
{
    cin >> G;
    while(G--)
    {
        cin >> n;
        p[0] = 1;
        for(register int i = 1; i <= n; ++i)
        {
            cin >> p[i];
            p[i] /= 1000;
            f[i - 1] = p[i - 1] * (1 - p[i]);
            p[i] *= p[i - 1];
        }
        f[n] = 0;
        for(register int i = 1; i <= n; ++i)
        {
            cin >> a[i];
            a[i] += a[i - 1];
        }
        for(register int i = 1; i <= n; ++i)
        {
            dp[i] = (a[i] + s[i - 1]) / (1 - f[i]);
            s[i] = dp[i] * f[i] + s[i - 1];
        }
        printf("%lf\n", dp[n]);
    }
    return 0;
}
参考程序

 

转载于:https://www.cnblogs.com/kcn999/p/10755800.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值