UVA

来源:互联网 发布:mysql进程意外终止 编辑:程序博客网 时间:2024/06/08 17:47

Back to Kernighan-Ritchie

题目大意:给出一个程序控制流程图,从每个结点出发到每个后继结点的概率都相等。当执行玩一个没有后继的结点后,整个程序终止,程序总是从编号为1的结点开始执行。对于若干查询结点,求出每个结点的期望执行次数。
解题思路:设结点i的出度为di,对于一个拥有3个前驱结点a,b,c的结点i,可以列出方程xi=xa/da+xb/db+xc/dc,对于结点1,可以理解为有一个虚拟结点0以概率1转移到结点1。
为了解决无穷大的问题,需要用高斯约当消元法。

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<vector>#include<algorithm>using namespace std;typedef long long LL;const double eps=1e-8;const int MAXN=105;typedef double Matrix[MAXN][MAXN];Matrix A;int n,d[MAXN];vector<int> pre[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]);    //与除了第i行外的其他行进行消元    for(k=0;k<n;k++)    {      if(k!=i)      {        for(j=n;j>=i;j--)        A[k][j]-=A[k][i]/A[i][i]*A[i][j];      }    }  }}int main(){    int cas=0;    while(scanf("%d",&n)!=EOF)    {      if(n==0) break;      memset(d,0,sizeof(d));      for(int i=0;i<n;i++) pre[i].clear();      int a,b;      while(scanf("%d%d",&a,&b)!=EOF)      {        if(a==0&&b==0) break;        a--;b--;        d[a]++;        pre[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<pre[i].size();j++)        {          A[i][pre[i][j]]-=1.0/d[pre[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("%.3f\n",fabs(A[u][u])<eps?0.0:A[u][n]/A[u][u]);      }    }    return 0;}/*31 22 32 10 0312331 22 33 10 033210*/