zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    WisDom .net开发框架设计 2
    多线程处理大数组
    C#核心语法
    怎样控制与复制相同的功能
    SQL 内存数据库的细节
    验证编辑方法(Edit method)和编辑视图(Edit view)
    上传图片检测其是否为真实的图片 防范病毒上传至服务器
    chrome切换hosts插件 hostsadmin
    程序托盘图标+右键弹出菜单
    30多年程序员生涯经验总结(成功源自于失败中的学习;失败则是因为容忍错误的横行)
  • 原文地址:https://www.cnblogs.com/cyb123456/p/5830834.html
Copyright © 2011-2022 走看看