2023“钉耙编程”联赛 Day 3 L 题 Inference 题解

原题描述

给定 m m m 个特征,你想基于大量的数据,再通过 Alice \text{Alice} Alice 的前 m − 1 m−1 m1 个特征的值推断出她的最后一个特征的值。

特征之间的关系可以表示为一个有向无环图,其中一个节点 A A A 指向一个节点 B B B 表示 B B B 是依赖于 A A A 的随机变量。

下面的公式可以根据其他数据计算 Alice \text{Alice} Alice 的最后一个特征的值的概率,其中 x i x_i xi 表示第 i i i 个特征, π ( x i ) \pi(x_i) π(xi) 表示指向 x i x_i xi 的节点, c n t cnt cnt 表示它们的出现次数:

P ( x m ∣ x 1 , … , x m − 1 ) = c P ( x 1 , … , x m ) = ∏ i = 1 m P ( x i ∣ π ( x i ) ) P(x_m∣x_1,\dots,x_{m−1})=cP(x_1,\dots,x_m)=\prod_{i=1}^m P(x_i∣\pi(x_i)) P(xmx1,,xm1)=cP(x1,,xm)=i=1mP(xiπ(xi))

P ( x i ∣ π ( x i ) ) = P ( π ( x i ) , x i ) P ( π ( x i ) ) = { c n t ( π ( x i ) , x i ) c n t ( π ( x i ) ) , if    c n t ( π ( x i ) ) ≠ 0 0 , if    c n t ( π ( x i ) ) = 0 P(x_i∣\pi(x_i))=\dfrac{P(\pi(x_i),x_i)}{P(\pi(x_i))}= \begin{cases} \dfrac{cnt(\pi(x_i),x_i)}{cnt(\pi(x_i))}, \text{if}\;cnt(\pi(x_i))\not=0 \\0,\text{if}\;cnt(\pi(x_i))=0 \end{cases} P(xiπ(xi))=P(π(xi))P(π(xi),xi)= cnt(π(xi))cnt(π(xi),xi),ifcnt(π(xi))=00,ifcnt(π(xi))=0

保证最后一个特征的出度为 0 0 0,并且至少存在一种情况使得 c n t ( π ( x i ) ) ≠ 0 cnt(\pi(x_i))\not =0 cnt(π(xi))=0

现在,给定 n n n个人的数据,假设已知她的前 m − 1 m−1 m1个特征的值,Alice 的第 m m m个特征最有可能是什么值。

(题面很垃圾,建议看一下然后看样例解释)

输入描述

输入部分的开头有一个整数 T T T ( 1 ≤ T ≤ 10 ) (1\leq T\leq 10) (1T10),表示测试用例的数量。

对于每个测试用例,第一行包含三个整数 n n n ( 1 ≤ n ≤ 1 0 4 ) , m (1\leq n\leq 10^4),m (1n104)m ( 1 ≤ m ≤ 100 ) , k (1\leq m\leq 100),k (1m100)k ( 1 ≤ k ≤ 300 ) (1\leq k\leq 300) (1k300),表示数据的数量、特征的数量以及特征之间的关系数量。

在接下来的 k k k 行中,每行包含两个整数 x , y x, y x,y ( 1 ≤ x , y ≤ m ) (1\leq x,y\leq m) (1x,ym),表示节点 x x x 指向节点 y y y,因此第 y y y 个特征依赖于第 x x x 个特征。每个节点的入度小于 5 5 5

在接下来的 n n n 行中,每行包含 m m m 个整数,表示某个人每个特征的值。每个特征的值在 0 、 1 、 2 0、1、2 012 之间。

在最后一行,有 m − 1 m-1 m1 个整数,表示 Alice \text{Alice} Alice 的前 m − 1 m-1 m1 个特征的值。

输出描述

输出一个整数,表示 Alice \text{Alice} Alice 的第 m m m 个特征的最可能的值。

保证只存在一个具有最大概率的值。

样例输入

1
10 5 4
1 4
2 4
3 5
4 5
0 1 0 1 0 
0 1 1 1 1 
0 0 0 0 0 
0 0 1 0 0 
1 1 1 0 1 
1 0 0 1 1 
1 1 0 1 1 
1 0 1 0 0 
1 1 1 1 1 
0 1 0 1 1 
1 1 0 0

样例输出

0

样例解释

在样例中,这里有十个人的数据,包含五个特点,特点有四个关系,这是一个反应每个人数据的表格:

编号 努力 处境 食欲 成绩 个性
1 0 1 0 1 0
2 0 1 1 1 1
3 0 0 0 0 0
4 0 0 1 0 0
5 1 1 1 0 1
6 1 0 0 1 1
7 1 1 0 1 1
8 1 0 1 0 0
9 1 1 1 1 1
10 0 1 0 1 1
Alice 1 1 0 0 ?

他们的关系如下:

2023“钉耙编程”联赛 Day 3 L 题 Inference 题解_第1张图片

我们可以使用公式来计算结果为 0 0 0 的概率:

P ( x m ∣ x 1 , … , x m − 1 ) = c P ( x 1 , … , x m ) = ∏ i = 1 m P ( x i ∣ π ( x i ) ) = P ( x 1 = 1 ) × P ( x 2 = 1 ) × P ( x 3 = 0 ) × P ( x 4 = 0 ∣ x 1 = 1 , x 2 = 1 ) × P ( x 5 = 0 ∣ x 3 = 0 , x 4 = 0 ) = 5 10 × 6 10 × 5 10 × 1 3 × 1 1 = 0.05 P(x_m∣x_1,\dots,x_{m−1})=cP(x_1,\dots,x_m)=\prod_{i=1}^m P(x_i∣\pi(x_i))\\ =P(x_1=1)\times P(x_2=1)\times P(x_3=0)\times P(x_4=0|x_1=1,x_2=1)\times P(x_5=0|x_3=0,x_4=0)\\ =\frac{5}{10}\times\frac{6}{10}\times\frac{5}{10}\times\frac{1}{3}\times\frac{1}{1}=0.05 P(xmx1,,xm1)=cP(x1,,xm)=i=1mP(xiπ(xi))=P(x1=1)×P(x2=1)×P(x3=0)×P(x4=0∣x1=1,x2=1)×P(x5=0∣x3=0,x4=0)=105×106×105×31×11=0.05
可以计算得出 1 , 2 1,2 1,2 的概率都等于 0 0 0,小于 0.05 0.05 0.05

做法解析

这道题纯纯诈骗题,我们关注下面样例解释的式子,我们发现对于每种可能,其概率与其他可能不同的地方只在最后一项,所以我们只关心这一项即可。

那么我们只需要找出与 x m x_m xm 有关的特点,筛选出条件符合的统计即可。

代码解析

#include 
#define LL long long
using namespace std;
const LL N = 1e4 + 5;
const LL M = 105;
const LL K = 305;
LL T, n, m, k, x, y, d[N][M], a[M], cnt[3];
vector<LL> v[N];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> T;
    while (T--) {
        memset(v, 0, sizeof(v));
        memset(cnt, 0, sizeof(cnt));
        cin >> n >> m >> k;
        for (int i = 1; i <= k; i++) {
            cin >> x >> y;
            v[y].push_back(x);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                cin >> d[i][j];
            }
        }
        for (int i = 1; i <= m - 1; i++) {
            cin >> a[i];
        }
        for (int i = 1; i <= n; i++) {
            LL f = 0;
            for (LL j : v[m]) {
                if (d[i][j] != a[j]) {
                    f = 1;
                    break;
                }
            }
            if (!f) {
                cnt[d[i][m]]++;
            }
        }
        LL ans = 0;
        for (int i = 1; i <= 2; i++) {
            if (cnt[ans] < cnt[i])
                ans = i;
        }
        printf("%lld\n", ans);
    }
}

你可能感兴趣的:(算法,学习,ACM,c++,思维)