每个顶点的概率

Probability for each vertex

本文关键字:概率 顶点      更新时间:2023-10-16

i有一个带有n个顶点和m边缘的图(n在1到15之间,m在1和n^2之间。该图是定向和加权的(具有该激发边缘的概率)。给您一个启动顶点和许多边缘。然后,该程序将计算每个顶点是末端顶点的概率。

检查输入:

3 3//顶点数量和边数

1 2 0.4//边缘NR.1从顶点1到2,概率为0.4

1 3 0.5//边缘NR.2从顶点1到3,概率为0.5

2 1 0.8//Edge Nr.3 ...

3//问题数

2 1//启动顶点,访问的边数

1 1

1 2

输出:

0.8 0.2 0.0//顶点1的概率beign beign beign the最后一个顶点为0.8,对于顶点2为0.2,对于顶点3,它是0.0

0.1 0.4 0.5

0.33 0.12 0.55

我在解决方案中使用了DFS,但是当访问的边缘数量最多可达10亿时,这太慢了...我一直在看DP,但我是不确定如何针对此特定问题实施它(即使是正确的解决方法)。因此,我希望你们中的一些人可以建议使用DFS和/或使用/实施DP的方法。

(我知道这可能有点混乱,我只在C 中编程一个月)

#include <iostream>
#include <vector>
#include <stack>
using namespace std;
struct bird {
    int colour;
    float probability;
};
struct path {
    int from;
    int to;
};
vector <vector <bird>> birdChanges;
vector <int> layer;
vector <double> savedAnswers;
stack <path> nextBirds;
int fromBird;
//Self loop
void selfLoop(){
    float totalOut = 0;
    for (int i = 0; i < birdChanges.size(); i++) {
        for (int j = 0; j < birdChanges[i].size(); j++) {
            totalOut += birdChanges[i][j].probability;
        }
        if (totalOut < 1) {
            bird a;
            a.colour = i;
            a.probability = 1 - totalOut;
            birdChanges[i].push_back(a);
        }
        totalOut = 0;
    }
}
double fillingUp(double momentarilyProbability, long long int numberOfBerries){
    int layernumber=0;
    while (layer[numberOfBerries - (1+layernumber)] == 0) {
        layernumber++;
        if (numberOfBerries == layernumber) {
            break;
        }
    }
    layernumber = layer.size() - layernumber;
    path direction;
    int b;
    if (layernumber != 0) {
        b= birdChanges[nextBirds.top().from][nextBirds.top().to].colour;//Usikker
    }
    else {
        b = fromBird;
    }
    while (layer[numberOfBerries - 1] == 0) {
        //int a = birdChanges[nextBirds.top().from][nextBirds.top().to].colour;
        if (layernumber != 0) {
            momentarilyProbability *= birdChanges[nextBirds.top().from][nextBirds.top().to].probability;
            //b = birdChanges[nextBirds.top().from][nextBirds.top().to].colour;
        }
        for (int i = 0; i < birdChanges[b].size(); i++) {
            direction.from = b;
            direction.to = i;
            //cout << endl << "Stacking " << b << " " << birdChanges[b][i].colour;
            nextBirds.push(direction);
            layer[layernumber]++;
        }
        layernumber++;
        b = birdChanges[nextBirds.top().from][nextBirds.top().to].colour;
    }
    //cout << "Returning" << endl;
    return momentarilyProbability *= birdChanges[nextBirds.top().from][nextBirds.top().to].probability;;
}
//DFS
void depthFirstSearch(int fromBird, long long int numberOfBerries) {
    //Stack for next birds (stack)
    path a;
    double momentarilyProbability = 1;//Momentarily probability (float)
    momentarilyProbability=fillingUp(1, numberOfBerries);
    //cout << "Back " << momentarilyProbability << endl;
    //Previous probabilities (stack)
    while (layer[0] != 0) {
        //cout << "Entering" << endl;
        while (layer[numberOfBerries - 1] != 0) {
            savedAnswers[birdChanges[nextBirds.top().from][nextBirds.top().to].colour] += momentarilyProbability;
            //cout << "Probability for " << birdChanges[nextBirds.top().from][nextBirds.top().to].colour << " is " << momentarilyProbability << endl;
            momentarilyProbability = momentarilyProbability / birdChanges[nextBirds.top().from][nextBirds.top().to].probability;
            nextBirds.pop();
            layer[numberOfBerries - 1]--;
            if (layer[numberOfBerries - 1] != 0) {
                momentarilyProbability *= birdChanges[nextBirds.top().from][nextBirds.top().to].probability;
            }
        }
        if (layer[0] != 0) {
            int k = 1;
            while (layer[layer.size() - k]==0&&k+1<=layer.size()) {
                //cout << "start" << endl;
                momentarilyProbability = momentarilyProbability / birdChanges[nextBirds.top().from][nextBirds.top().to].probability;
                //cout << "Popping " << nextBirds.top().from << birdChanges[nextBirds.top().from][nextBirds.top().to].colour << endl;
                nextBirds.pop();
                //cout << "k " << k << endl;
                layer[numberOfBerries - 1 - k]--;
                k++;
                //cout << "end" << endl;
            }
        }
        if (layer[0] != 0) {
            //cout << 1 << endl;
            //cout << "Filling up from " << nextBirds.top().from << birdChanges[nextBirds.top().from][nextBirds.top().to].colour << endl;
            momentarilyProbability = fillingUp(momentarilyProbability, numberOfBerries);
        }
    }
    //Printing out
    for (int i = 1; i < savedAnswers.size(); i++) {
        cout << savedAnswers[i] << " ";
    }
    cout << endl;
}
int main() {
    int numberOfColours;
    int possibleColourchanges;
    cin >> numberOfColours >> possibleColourchanges;
    birdChanges.resize(numberOfColours+1);
    int from, to;
    float probability;
    for (int i = 0; i < possibleColourchanges; i++) {
        cin >> from >> to >> probability;
        bird a;
        a.colour = to;
        a.probability = probability;
        birdChanges[from].push_back(a);
    }
    selfLoop();
    int numberOfQuestions;
    cin >> numberOfQuestions;
    long long int numberOfBerries;
    for (int i = 0; i < numberOfQuestions; i++) {
        cin >> fromBird >> numberOfBerries;
        savedAnswers.assign(numberOfColours + 1, 0);
        layer.resize(numberOfBerries, 0);
        //DFS
        depthFirstSearch(fromBird, numberOfBerries);
    }
    system("pause");
}

快速解释如何使用马尔可夫链的概念做到这一点:

Basic algorithm:
Input: starting configuration vector b of probabilities of
    being in a vertex after 0 steps,
    Matrix A that stores the probability weights,
    in the scheme of an adjacency matrix
    precision threshold epsilon
Output: 
    an ending configuration b_inf of probabilities after infinite steps
Pseudocode:
    b_old = b
    b_new = A*b
    while(difference(b_old, b_new) > epsilon){
        b_old = b_new
        b_new = A*b_old
    }
    return b_new

在此算法中,我们本质上是计算概率矩阵的效力,并寻找何时变得稳定。

b是没有采取任何步骤后在顶点处的概率(因此,在您的情况下,除了开始顶点外,每个条目都是零,这是一个)

a*b是一步之后的那些

a^2 * b是完成两个步骤后的a^n * b之后的

a^n * b。

当a^n * b与a^n-1 * b几乎相同时,我们认为它不会再发生大的,它基本上与a^infinity * b

相同

一个人可以用一些示例模拟该算法,例如一个带有很小概率的边缘的边缘,这将导致一个在无限步骤之后的概率1中导致一个子图中,但例如,从现实来看,它会起作用。

为了差异,欧几里得距离应该很好地工作,但是从本质上讲,您也可以使用最大或曼哈顿。

请注意,我提出了一种务实的观点,数学家将更多地详细介绍它的属性将收敛于epsilon的哪个值的速度。

您可能想将良好的库用于矩阵,例如eigen。

编辑:

阅读Jarod42的评论,我意识到您的步骤数量已得到。在这种情况下,只需使用a^step * b进行精确解决方案即可。使用一个好的库来快速计算效力。