Time:2016.08.18
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
某条边的期望=该边的概率*编号
有一种贪心思路就是把边按照概率从大到小排序,然后从1-m赋值计算即可
问题就转化成求每条边的概率
对于
E(u,v)
来说
PE=Pu∗du+Pv∗dv
问题又转化成求每个点的概率
对于每个点建立一个n元方程,联立解得即可
注意:
P1
是比其他点的概率要大1的,因为起点是1
Pn=0
,因为不能从n走出来
代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define eps 1e-6
using namespace std;
int tot,n,m;
int I[505],first[505];
double f[505][505],ans[505],P[250005];
struct edge{
int u,v,next;
}e[250005];
int in()
{
int t=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<3)+(t<<1)+ch-48,ch=getchar();
return t;
}
int dcmp(double x,double y)
{
if (fabs(x-y)<=eps) return 0;
return x>y?1:-1;
}
void add(int x,int y)
{
e[++tot]=(edge){x,y,first[x]};first[x]=tot;I[x]++;
e[++tot]=(edge){y,x,first[y]};first[y]=tot;I[y]++;
}
void gauss()
{
int t;double p;
for (int i=1;i<=n;++i)
{
int t=i;
for (int j=i+1;j<=n;++j)
if (dcmp(fabs(f[t][i]),fabs(f[j][i]))==-1) t=j;
if (t!=i)
for (int j=i;j<=n+1;++j)
swap(f[t][j],f[i][j]);
for (int j=i+1;j<=n;++j)
{
p=f[j][i]/f[i][i];
for (int k=i+1;k<=n+1;++k)
f[j][k]-=f[i][k]*p;
}
}
for (int i=n;i;--i)
{
p=0;
for (int j=i+1;j<=n;++j) p+=ans[j]*f[i][j];
ans[i]=(f[i][n+1]-p)/f[i][i];
}
}
main()
{
n=in();m=in();
for (int i=1;i<=m;++i)
add(in(),in());
for (int i=1;i<=n;++i)
{
for (int j=first[i];j;j=e[j].next)
if (e[j].v!=n)
f[i][e[j].v]=1.0/I[e[j].v];
f[i][i]=-1;
f[i][n+1]=-(i==1);
}
gauss();
ans[n]=0;
for (int i=1;i<=tot;i+=2)
P[(i+1)>>1]=1.0/I[e[i].u]*ans[e[i].u]+1.0/I[e[i].v]*ans[e[i].v];
sort(P+1,P+m+1);
for (int i=m;i;--i)
P[0]+=P[i]*(m-i+1);
printf("%.3lf",P[0]);
}