UVa10828

10828 Back to Kernighan-Ritchie
You must have heard the name of Kernighan and Ritchie, the authors of
The C Programming Language. While coding in C, we use different control
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;
In the above code, there is a bias in each conditional branch. Such
codes can be represented by control flow graphs like below:
Let the probability of jumping from one node of the graph to any of its adjacent nodes be equal.
So, in the above code fragment, the expected number of times U executes is 2. In this problem, you
will be given with such a control flow graph and find the expected number of times a node is visited
starting from a specific node.
Input
Input consists of several test cases. There will be maximum 100 test cases. Each case starts with an
integer: n (n  100). Here n is the number of nodes in the graph. Each node in the graph is labeled
with 1 to n and execution always starts from 1. Each of the next few lines has two integers: start and
end which means execution may jump from node start to node end. A value of zero for start ends this
list. After this, there will be an integer q (q  100) denoting the number of queries to come. Next q
lines contain a node number for which you have to evaluate the expected number of times the node is
visited. The last test case has value of zero for n which should not be processed.
Output
Output for each test case should start with ‘Case #i:’ with next q lines containing the results of the
queries in the input with three decimal places. There can be situations where a node will be visited
forever (for example, an infinite for loop). In such cases, you should print ‘infinity’ (without the
quotes). See the sample output section for details of formatting.
Universidad de Valladolid OJ: 10828 – Back to Kernighan-Ritchie 2/2
Sample Input
31
2
2 3
2 1
0 0
312331
2
2 3
3 1
0 0
33210
Sample Output
Case #1:
2.000
2.000
1.000
Case #2:
infinity
infinity
infinity

题意:

       给出一个程序控制流图,从每个结点出发到每个后继结点的概率相等。当执行完一个没有后继的结点后,整个程序终止。程序总是从编号为1的结点开始执行。你的任务是对于若干个查询结点,求出每个结点的期望执行次数。

分析:

       这道题是关于马尔可夫过程的。设结点i的出度为di,期望执行次数是xi。对于一个拥有3个前驱结点a,b,c的结点i,可以列出方程xi=xa/da+xb/db+xc/dc。

       由于要达到结点i必须先经过结点i的前驱结点a,而弧aài的期望经过次数是xa/da。根据期望的线性性质,上述方程成立。

       注意到结点1比较特殊,可以加一个虚拟结点0,并且结点0以概率1转移到结点1。

       下面就可以根据题目给出的转移边写出一个方程组并求解。但是需要注意的是输出的答案可能是无穷大,这是因为流图中出现了环,并且可以无限地循环下去。这样高斯消元后得到的方程中存在矛盾方程。

       除此之外,高斯消元后还可能得到一些无用方程,从而导致一些变量的值无法确定,这是因为有一些结点无法从起点通过转移到达,这些结点的执行次数期望其实是0。

       在解方程的过程中,用数组inf来存储那些无穷变量。

 1 #include <algorithm>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <vector>
 6 const double eps = 1e-8;
 7 const int maxn = 100;
 8 typedef double Matrix[maxn + 1][maxn + 1];
 9 // 由于本题的特殊性,消元后不一定形成对角阵甚至阶梯形矩阵
10 // 按照此处的消元方式,如果x[i]有唯一解,那么第i行除了A[i][i]和A[i][n]之外的其它元素皆是零
11 void gauss_jordan_changed_version(Matrix A,int n){
12     int i,j,k,r;
13     for(i = 0 ; i < n ; i++){
14         r = i;
15         for(j = i + 1 ; j < n ; j++)if(fabs(A[j][i]) > fabs(A[r][i])) r = j;
16         if(fabs(A[r][i]) < eps) continue;// 这行对应的要么是矛盾方程要么是无用方程
17         if(r != i) for(j = 0 ; j <= n ; j++) std::swap(A[r][j],A[i][j]);
18         // 与除了第i行的其它行进行消元
19         for(k = 0 ; k < n ; k++)if(k != i)
20             for(j = n ; j >= i ; j--) A[k][j] -= A[k][i] / A[i][i] * A[i][j];
21     }
22     // 注意由于本题可能存在INF解,所以在此省略回代的过程
23 }
24 Matrix A;
25 int n,d[maxn + 1]; // d[i]代表结点i的出度
26 std::vector<int> prev[maxn + 1]; // prev[i][j]代表结点i的第j个前驱结点
27 int inf[maxn + 1]; // 存储那些对应inf期望值的结点
28 int main(){
29     int kase = 0;
30     while(scanf("%d",&n) == 1 && n){
31         memset(d,0,sizeof d);
32         for(int i = 0 ; i < n ; i++) prev[i].clear();
33         int a,b;
34         while(scanf("%d%d",&a,&b) == 2 && a){
35             a--,b--,d[a]++;
36             prev[b].push_back(a);
37         }
38         // 构造方程组
39         memset(A,0,sizeof A);
40         for(int i = 0 ; i < n ; i++){
41             A[i][i] = 1;
42             for(int j = 0 ; j < prev[i].size() ; j++)
43                 A[i][prev[i][j]] -= 1.0 / d[prev[i][j]];
44             if(i == 0) A[i][n] = 1;
45         }
46         // 解方程组,标记无穷变量
47         gauss_jordan_changed_version(A,n);
48         memset(inf,0,sizeof inf);
49         for(int i = n - 1 ; i >= 0 ; i--){
50             // 直接解出来的无穷变量
51             if(fabs(A[i][i]) < eps && fabs(A[i][n]) > eps) inf[i] = 1;
52             for(int j = i + 1 ; j < n ; j++)
53                 // 和无穷变量扯上关系的变量也是无穷的
54                 if(fabs(A[i][j]) > eps && inf[j]) inf[i] = 1;
55         }
56         int q,u; scanf("%d",&q);
57         printf("Case #%d:
",++kase);
58         while(q--){
59             scanf("%d",&u); u--;
60             if(inf[u]) printf("infinity
");
61             else printf("%.3lf
",fabs(A[u][u]) < eps ? 0.0 : A[u][n] / A[u][u]);
62         }
63     }
64     return 0;
65 }
View Code
原文地址:https://www.cnblogs.com/cyb123456/p/5830834.html