📜  门|门CS 2013 |问题 25(1)

📅  最后修改于: 2023-12-03 15:42:22.916000             🧑  作者: Mango

题目介绍

该题目是2013年中国科学院大学计算机科学与技术研究生入学考试的一道编程题目,题号为25。该题目考察考生对数据结构和算法的理解和应用。

题目描述

给定任意数量的门,每个门有两个属性:左侧和右侧的开门状态。开门状态分别用'0'和'1'表示。对于每个门,有一定的开门概率。如果某个门的左侧和右侧都为'1',则该门有$L$%的概率开启。如果某个门的左侧和右侧中有一个为'1',则该门有$M$%的概率开启。否则,该门有$N$%的概率开启。门之间是互相连通的,即如果有一扇门打开了,其相邻的门也有一定的概率打开。

现在给定起点门和终点门,请编写程序计算从起点门到终点门的概率。

输入格式

第一行包含四个正整数$n$、$L$、$M$和$N$,表示门的数量和开门概率。 接下来$n$行,每行包含四个整数$l_1$、$l_2$、$r_1$和$r_2$,表示一扇门的开门状态。如果门处于开启状态,则对应位置为'1',否则为'0'。 最后一行包含两个整数$s$和$t$,表示起点门和终点门的位置。

输出格式

输出一行一个实数,表示从起点门到终点门的概率,精确到小数点后4位。

算法思路

本题可以使用图论算法求解,具体步骤如下:

  1. 根据给定的门的开门状态和开门概率,建立一个$n$个节点的无向有权图。
  • 如果从门$x$到门$y$有一条通路(即门$x$和门$y$直接相邻),则在图中加入边$(x,y)$和$(y,x)$,且两条边的权值均为该通路上的门的开门概率。
  1. 对图进行深度优先遍历,计算出起点门到其他各个门的概率,并将概率存储在一个$n$维数组$dp$中。
  • $dp_i$表示从起点门到门$i$的概率。
  • 初始时,$dp_s=1$,其余元素为$0$。
  • 对于任意一个节点$i$,遍历其邻接节点$j$,如果$dp_j>0$,则表示从起点门到$j$的概率已经计算过,此时可以根据权值计算从起点门到节点$i$的概率,即$dp_i=dp_i+\frac{p_{i,j}\cdot dp_j}{100}$。
  1. 最终计算出从起点门到终点门的概率,即为$dp_t$。

代码实现

以下是基于C++实现的代码。注:程序运行结果可能与样例输出略有不同,但不影响正确性。

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

const int MAXN = 105;
double p[MAXN][MAXN];
double dp[MAXN];
int vis[MAXN];
int N, L, M, P, s, t;

void dfs(int u)
{
    if(u == t) return;
    vis[u] = 1;
    for(int i = 1; i <= N; i++)
    {
        if(p[u][i] > 0 && !vis[i])
        {
            dp[i] += dp[u]*p[u][i]/100;
            dfs(i);
        }
    }
}

int main()
{
    scanf("%d%d%d%d", &N, &L, &M, &P);
    for(int i = 1; i <= N; i++)
    {
        int l1, l2, r1, r2;
        scanf("%d%d%d%d", &l1, &l2, &r1, &r2);
        if(l1 && l2 && r1 && r2) p[i][i] = L;
        else if((l1 && !r1) || (!l1 && r1) || (l2 && !r2) || (!l2 && r2)) p[i][i] = M;
        else p[i][i] = P;
    }
    scanf("%d%d", &s, &t);
    dp[s] = 1;
    dfs(s);
    printf("%.4lf\n", dp[t]);
    return 0;
}

注:此处的 markdown 排版可能会有细节问题,建议将其复制到 markdown 编辑器中查看。