我有一个包含N个顶点和M个边的图(N介于1和15之间,M介于1和N ^ 2之间)。对图进行定向和加权(具有该精确边缘的概率)。您将获得一个起始顶点和许多边。然后程序将计算每个顶点作为结束顶点的概率。
考试输入:
3 3 //顶点数和边数
1 2 0.4 //从顶点1到2的边界nr.1,概率为0.4
1 3 0.5 //从顶点1到3的边界nr.2,概率为0.5
2 1 0.8 // Edge nr.3 ...
3 //问题数量
2 1 //开始顶点,要访问的边数
1 1
1 2
输出:
0.8 0.2 0.0 //对于顶点2,顶点1对最后一个顶点的概率为0.8,对于顶点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");
}
答案 0 :(得分:0)
使用马尔可夫链的概念快速解释如何做到这一点:
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是经过两个步骤后的那些,在n步之后A ^ n * b。
当A ^ n * b与A ^ n-1 * b几乎相同时,我们假设它不再发生任何大的变化,它基本上与A ^ infinity * b相同
可以用一些例子来模拟这个算法,例如在子图中以非常小的概率引导的边缘将导致一个在无限步骤之后以概率1存在于子图中,但是例如从现实中,它将起作用。
对于差异,欧几里德的距离应该很好,但基本上任何规范都可以,你也可以选择最大值或曼哈顿。
请注意,我提出了一个实用的观点,数学家会更详细地了解A的属性,它将汇集epsilon值的多快。
您可能希望使用一个好的库作为矩阵,例如Eigen。
编辑:
阅读Jarod42的评论,我意识到你已经给出了大量的步骤。在这种情况下,只需使用A ^步骤* b来获得确切的解决方案。使用一个好的库来快速计算效力。