【问题标题】:Probability for each vertex每个顶点的概率
【发布时间】:2017-07-14 03:13:16
【问题描述】:

我有一个包含 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 //从顶点1到3的边nr.2,概率为0.5

2 1 0.8 //边 nr.3...

3 //问题数

2 1 //起始顶点,要访问的边数

1 1

1 2

输出:

0.8 0.2 0.0 //顶点1出现最后一个顶点的概率为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");
}

【问题讨论】:

标签: c++ graph probability vertex edges


【解决方案1】:

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

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 是经过n步后的。

当A^n * b与A^n-1 * b几乎相同时,我们假设它不会再有大事发生,它与A^infinity * b基本相同

人们可以用一些例子来模拟这个算法,比如一条边以非常小的概率在子图中领先,这将导致一个在无限步后以概率 1 出现在子图中,但例如从现实来看,它会起作用。

对于差异,欧几里得距离应该可以很好地工作,但基本上任何规范都可以,您也可以使用最大值或曼哈顿。

请注意,我提出了一个务实的观点,数学家会更详细地了解 A 在哪些属性下,它会以多快的速度收敛到哪些 epsilon 值。

您可能希望为此使用一个好的矩阵库,例如 Eigen。

编辑:

阅读 Jarod42 的评论,我意识到您的步数已给出。在这种情况下,只需使用 A^steps * b 即可获得确切的解决方案。使用一个好的库来快速计算效力。

【讨论】:

  • 请注意,对于 OP,步数是给定的
  • 嗯,你说得对。编辑了我的答案。不想删除文本,因为它可能在未来的某个时间与他有关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-21
  • 2018-04-19
  • 2019-02-20
  • 2023-03-27
  • 2023-03-20
  • 1970-01-01
  • 2016-01-28
相关资源
最近更新 更多