Youmust have heard the name of Kernighan and Ritchie, the authors ofThe C Programming Language. While coding in
C, we use differentcontrol statements and loops, such as, if-then-else,
for, do-while,etc. Consider the following fragment of pseudo code:
//execution starts here
do {
U;
V;
} while(condition);
W;
Inthe above code, there is a bias in each conditional branch. Such codes can berepresented by control flow graphs like below:
Letthe probability of jumping from one node of the graph to any of its adjacentnodes be equal. So, in the abovecode fragment, the expected number of times U executes is 2. Inthis problem, you will be given with such a control flow graph and find theexpected
number of times a node is visited starting from a specific node.
Input
Inputconsists of several test cases. There will be maximum 100 test cases. Each case starts with an integer: n (n ≤ 100).Here nis the number of nodes in the graph. Each node in the graph is labeled with 1 ton and execution always starts from 1. Each of the
next few lines has twointegers: startand endwhich means execution may jump from node start to node end. A value of zero for start endsthis list. After this, there will be an integer q (q ≤ 100) denoting the numberof queries to come. Next q lines contain a
node number for which you have to evaluate theexpected number of times the node is visited. The last test case has value ofzero for nwhich should not be processed.
Output
Output for each test caseshould start with “Case #i:”with next q lines containing the results of the queries in the input with threedecimal places. There can be situations where a node will be visited forever(for example, an infinite forloop). In such cases,
you should print “infinity” (without the quotes). See thesample output section for details of formatting.
Sample Input Output for Sample Input
3 1 2 2 3 2 1 0 0 3 1 2 3 3 1 2 2 3 3 1 0 0 3 3 2 1 0 |
Case #1: 2.000 2.000 1.000 Case #2: infinity infinity infinity |
Problem setter: Mohammad Sajjad Hossain
Special Thanks: Shahriar Manzoor
题意:从每个结点出发到每个后继结点的概率均相等,当执行完一个没有后继结点后,整个过程停止,程序从编号为1的结点开始执行,你的任务是对于若干个查询点,求出每个结点的期望执行次数
思路:对于这道题目我们可以转换成方程:xi = xa/da + xb/db + xc/dc+...,设i的出度为di,期望执行的次数为xi,xa等是它的前驱。但是这道题目又与其他的解方程题目不一样,就是可以会有无穷大的矛盾方程或者出现多余方程,所以我们需要用高斯—约当消元法来省略回代过程,同时还要处理无穷解的可能
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> #include <vector> using namespace std; const int maxn = 110; const double eps = 1e-8; typedef double Matrix[maxn][maxn]; Matrix A; int n, d[maxn]; vector<int> prev[maxn]; int inf[maxn]; void gauss_jordan(Matrix A, int n) { int i, j, k, r; for (i = 0; i < n; i++) { r = i; for (j = i+1; j < n; j++) if (fabs(A[j][i]) > fabs(A[r][i])) r = j; if (fabs(A[r][i]) < eps) continue; if (r != i) for (j = 0; j <= n; j++) swap(A[r][j], A[i][j]); for (k = 0; k < n; k++) if (i != k) for (j = n; j >= i; j--) A[k][j] -= A[k][i] / A[i][i] * A[i][j]; } } int main() { int cas = 1; while (scanf("%d", &n) != EOF && n) { memset(d, 0, sizeof(d)); for (int i = 0; i < n; i++) prev[i].clear(); int a, b; while (scanf("%d%d", &a, &b) != EOF && a) { a--, b--; d[a]++; prev[b].push_back(a); } memset(A, 0, sizeof(A)); for (int i = 0; i < n; i++) { A[i][i] = 1; for (int j = 0; j < prev[i].size(); j++) A[i][prev[i][j]] -= 1.0 / d[prev[i][j]]; if (i == 0) A[i][n] = 1; } gauss_jordan(A, n); memset(inf, 0, sizeof(inf)); for (int i = n-1; i >= 0; i--) { if (fabs(A[i][i]) < eps && fabs(A[i][n]) > eps) inf[i] = 1; for (int j = i+1; j < n; j++) if (fabs(A[i][j]) > eps && inf[j]) inf[i] = 1; } int q, u; scanf("%d", &q); printf("Case #%d:\n", cas++); while (q--) { scanf("%d", &u); u--; if (inf[u]) printf("infinity\n"); else printf("%.3lf\n", fabs(A[u][u]) < eps ? 0.0 : A[u][n] / A[u][u]); } } return 0; }