UVA 10828 Back to Kernighan-Ritchie 高斯约当消元

#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
*/



你可能感兴趣的:(期望,高斯约当消元)