UVA10828 - Back to Kernighan-Ritchie

链接

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1769

题解

黑心?出题人qwq(就不能写个spj吗
这题是高斯消元,每个点的期望次数等于它的所有前驱的(期望次数/前驱的出度)之和, 1 1 1号结点还要 + 1 +1 +1
由于是任意的图,所以很容易发现这个东西没法 d p dp dp
考虑求解我列出的方程组,有些变量是解不出来的
比如下面这个情形:
1 → 2 1\rightarrow2 12
2 → 1 2\rightarrow1 21
3 → 1 3\rightarrow1 31
列出方程组:
{ e 1 = 1 + e 2 + e 3 e 2 = 0.5 e 1 e 3 = 0.5 e 1 \begin {cases} e_1=1+e_2+e_3\\ e_2=0.5e_1\\ e_3=0.5e_1 \end {cases} e1=1+e2+e3e2=0.5e1e3=0.5e1
消元得到了 0 = 1 0=1 0=1这样的等式
这样的情况下我确实得不到一个有界量来表示 e 1 , e 2 , e 3 e_1,e_2,e_3 e1,e2,e3
在实际情况中,这样的点应该是输出 i n f inf inf
用高斯消元作处理之后,这样的变量表现出来的特点是系数为 0 0 0且常数项不等于 0 0 0
这题有个精度的问题:
不要把 e i e_i ei的值提前算出来,因为算的时候你要除以系数,假如没除以系数之前常数项存的是 − 0.0000000000001 -0.0000000000001 0.0000000000001,而实际上这里应该是 0 0 0,如果用 e p s eps eps判一下,你输出的是 0 0 0(正确√),但是假设系数很小,等于 0.00000000001 0.00000000001 0.00000000001,那么你做完除法之后再判 e p s eps eps,你就会认为这个数字不等于 0 0 0,从而你输出了 − 0.000 -0.000 0.000(错误×)
出题人就不会写一个 s p j spj spj么qwq

代码

#include 
#define eps 1e-8
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define maxn 110
#define base 2000
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
int read(int x=0)
{
	int c, f=1;
	for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
	for(;isdigit(c);c=getchar())x=x*10+c-48;
	return f*x;
}
int cd[maxn], N, road[maxn][maxn], inf[maxn];
double mat[maxn][maxn], ans[maxn];
void gauss(double (*m)[maxn], int n)
{
	int i, j, k, r;
	for(i=1;i<=n;i++)
	{
		r=i;
		for(j=i+1;j<=n;j++)if(fabs(m[j][i])>fabs(m[r][i]))r=j;
		if(fabs(m[r][i])<eps)continue;
		for(j=1;j<=n+1;j++)swap(m[i][j],m[r][j]);
		for(j=1;j<=n;j++)
			if(j!=i)
			{
				for(k=n+1;k>=i;k--)m[j][k]-=m[j][i]/m[i][i]*m[i][k];
			}
	}
}
void init()
{
	int i, j, a, b;
	cl(inf), cl(mat), cl(cd), cl(ans), cl(road);
	while(a=read(), b=read(), a)
	{
		road[a][b]=1;
	}
	for(i=1;i<=N;i++)for(j=1;j<=N;j++)if(i!=j and road[i][j])cd[i]++;
	for(i=1;i<=N;i++)mat[i][i]=1;
	for(i=1;i<=N;i++)for(j=1;j<=N;j++)
	{
		if(i!=j and road[i][j])
		{
			mat[j][i]=-1.0/cd[i];
		}
	}
	mat[1][N+1]=1;
}
void work()
{
	int i, j;
	gauss(mat,N);
	for(i=N;i;i--)
	{
		if(fabs(mat[i][i])<eps and fabs(mat[i][N+1])>eps)
		{
			inf[i]=1;
		}
		for(j=i+1;j<=N;j++)if(fabs(mat[i][j])>eps and inf[j])inf[i]=1;
		ans[i]=mat[i][N+1]/mat[i][i];
	}
}
int main()
{
	int q, x, kase=0;
	while(N=read())
	{
		printf("Case #%d:\n",++kase);
		init();
		work();
		q=read();
		while(q--)
		{
			x=read();
			if(inf[x])
			{
				printf("infinity\n");
			}
			else printf("%.3lf\n",fabs(mat[x][N+1])<eps ? 0.0 :mat[x][N+1]/mat[x][x]);
		}
	}
	return 0;
}

你可能感兴趣的:(#,线性代数)