UVA 10828 Back to Kernighan-Ritchie 高斯约当消元
来源:互联网 发布:flux软件 编辑:程序博客网 时间:2024/04/29 02:47
#include <cstdio>#include <cstring>#include <cmath>#include <vector>#include <iostream>#include <algorithm>using namespace std;const double eps=1e-8;const int maxn=111;typedef double matrix[maxn][maxn];void gauss_jordan(matrix e,int n)//高斯约当消元,即消成对角矩阵{ int i,j,k,r; for(i=0;i<n;i++) { r=i; for(j=i+1;j<n;j++) if(fabs(e[j][i])>fabs(e[r][i]))r=j; //当e[i][i]为0时,如果解为0,则其他行可忽略xi;若解为无穷,则其他相关行必为无穷。所以可以直接省略处理 if(fabs(e[r][i])<eps)continue; if(r!=i)for(j=0;j<=n;j++)swap(e[r][j],e[i][j]);//为了提高数值稳定性 for(k=0;k<n;k++)if(k!=i) for(j=n;j>=i;j--)e[k][j]-=e[k][i]/e[i][i]*e[i][j]; /* 高斯消元,即消成上三角矩阵 for(k=i+1;k<n;k++) { double f=e[k][i]/e[i][i]; for(j=i;j<=n;j++)e[k][j]-=f*e[i][j]; } */ }}matrix e;int n;int d[maxn];//各点的出度vector <int>pre[maxn];//各点的前驱结点int f[maxn];int main(){ int tt=0; while(scanf("%d",&n)!=EOF) { int i,j,k,a,b,t,u; if(n==0) break; memset(d,0,sizeof(d)); for(i=0;i<n;i++) pre[i].clear(); while(scanf("%d%d",&a,&b)==2&&a&&b) { a--; b--; d[a]++; pre[b].push_back(a); } memset(e,0,sizeof(e)); for(i=0;i<n;i++) { e[i][i]=1; for(j=0;j<pre[i].size();j++) e[i][pre[i][j]]-=1.0/d[pre[i][j]]; if(i==0) e[i][n]=1;//开始结点,期望+1; } gauss_jordan(e,n); memset(f,0,sizeof(f));//标记无穷变量 for(i=n-1;i>=0;i--) { if(fabs(e[i][i])<eps&&fabs(e[i][n])>eps){f[i]=1;continue;} for(j=i+1;j<n;j++) if(fabs(e[i][j])>eps&&f[j])f[i]=1;//与无穷变量相关的变量也是无穷变量 } scanf("%d",&t); printf("Case #%d:\n",++tt); while(t--) { scanf("%d",&u); u--; if(f[u])printf("infinity\n"); else printf("%.3lf\n",fabs(e[u][u])<eps?0.0:e[u][n]/e[u][u]); } } return 0;}/*注意点: 1.期望:设结点i的出度为di,期望执行次数为xi。对于一个有3个前驱结点a,b,c的结点i,可以列出方程xi=xa/da+xb/db+xc/dc。 2.对于开始结点结点,还要加上虚拟结点过来的期望1 3.当e[i][i]=e[i][n]=0时,xi=0;当e[i][i]=0,e[i][n]>0时,xi为正无穷。用高斯约当消元法求时。题中图可列方程组: x1=1+1/2*x2 x2=x1 x3=1/2*x2*/