将我隐藏,成为星空中崭新的孤岛|

cc0000

园龄:5年1个月粉丝:14关注:5

[HNOI2013] 游走

题面

一条边如果期望走的次数越少,那么我们就要给他分配更大的标号,所以我们需要求出每一条边的被走过的次的期望。

而一条边被走过次数的期望就是 fxdx+fydyf 表示一个点被走过的期望,d 表示一个点的度数。

然后就变成了一道经典的高斯消元,列方程求出 fx 。需要注意的是 f1=1+fxdxfn=0

#include <bits/stdc++.h>
using namespace std;
const int maxm=125002;
const int maxn=1002;
const double eps=1e-10;
typedef double db;
int n,m;
int X[maxm],Y[maxm];int d[maxn];
db a[maxn][maxn];db ans[maxm];

void solve()
{
	int r=0;db t;
	for(int i=1;i<=n;i++)
	{
		r=i;
		for(int j=i+1;j<=n;j++)
		{
			if(fabs(a[j][i])-fabs(a[r][i])>eps) 
				r=j;
		}
		if(fabs(a[r][i])<eps) return;
		if(r!=i) swap(a[r],a[i]);
		for(int k=i+1;k<=n;k++)
		{
			db ls=a[k][i]/a[i][i];
			for(int j=i;j<=n+1;j++)
				 a[k][j]-=ls*a[i][j];
		}
	}
	for(int i=n;i>=1;i--)
	{
		for(int j=i+1;j<=n;j++)
			a[i][n+1]-=a[j][n+1]*a[i][j];
		a[i][n+1]/=a[i][i];
	}
}
int main()
{
	//freopen("p.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&X[i],&Y[i]);
		d[X[i]]++;d[Y[i]]++;
		if(X[i]!=n) a[X[i]][Y[i]]=-1.0/d[Y[i]];
		if(Y[i]!=n) a[Y[i]][X[i]]=-1.0/d[X[i]];
	}
	for(int i=1;i<=m;i++)
	{
		if(X[i]!=n) a[X[i]][Y[i]]=-1.0/d[Y[i]];
		if(Y[i]!=n) a[Y[i]][X[i]]=-1.0/d[X[i]];
	}
	a[1][n+1]=1.0;
	for(int i=1;i<n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i==j) a[i][j]=1;
			//else a[i][j]=-1.0/d[j];
		}
	}
	a[n][n+1]=0;a[n][n]=1;
	solve();
	//for(int i=1;i<=n;i++)
	//	fprintf(stderr,"%.5f\n",a[i][n+1]);
	for(int i=1;i<=m;i++)
	{
		ans[i]=a[X[i]][n+1]/d[X[i]]+a[Y[i]][n+1]/d[Y[i]];
	}
	sort(ans+1,ans+1+m);
	db ret=0;
	for(int i=1;i<=m;i++)
	{
		ret+=ans[i]*(m-i+1);
	}
	printf("%.3lf",ret);
}

本文作者:cc0000

本文链接:https://www.cnblogs.com/cc0000/p/16808169.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   cc0000  阅读(168)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起