BZOJ 3143: [Hnoi2013]游走

HNOI2013 get!

高斯消元求出每个点经过的次数的期望,然后算出每条边的期望

然后套排序原理,乱序和最小

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define double long double
const int N=500+5;
const double eps=1e-9;
double g[N][N];
void Gauss(int n){
	for(int i=1;i<=n;i++){
		int j;
		for(j=i;j<=n;j++)
		if(fabs(g[j][i])>eps)break;
		for(int k=i;k<=n;k++)swap(g[i][k],g[j][k]);
		for(j=i+1;j<=n;j++){
			double t=g[j][i]/g[i][i];
			for(int k=i;k<=n+1;k++)
			g[j][k]-=t*g[i][k];
		}
	}
	for(int i=n;i>=1;i--){
		for(int j=i+1;j<=n;j++)
		g[i][n+1]-=g[j][n+1]*g[i][j];
		g[i][n+1]/=g[i][i];
	}
}
bool e[N][N];
double deg[N];
double path[N*N];
int main(){
	//freopen("a.in","r",stdin);
	int n,m;scanf("%d%d",&n,&m);
	while(m--){
		int u,v;scanf("%d%d",&u,&v);
		e[u][v]=e[v][u]=1;
		deg[u]+=1.0;deg[v]+=1.0;
	}
	for(int i=1;i<=n;i++){
		g[i][i]=1.0;
		for(int j=1;j<=n;j++)
		if(e[j][i])g[i][j]-=1.0/deg[j];
		g[i][n]=0.0;
	}
	g[n][n]=0.0;g[1][n]=1.0;
	Gauss(n-1);
	double ans=0.0;
	int tot=0;
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	if(e[i][j])path[++tot]=g[i][n]/deg[i]+g[j][n]/deg[j];
	sort(path+1,path+1+tot);
	for(int i=1;i<=tot;i++)
	ans+=path[i]*(tot-i+1);
	printf("%.3Lf\n",ans);
	return 0;
}


你可能感兴趣的:(BZOJ 3143: [Hnoi2013]游走)