「HNOI 2013」游走

传送门


problem

一个无向连通图,顶点从 1 1 1 编号到 n n n,边从 1 1 1 编号到 m m m

Z 在该图上进行随机游走,初始时小 Z 1 1 1 号顶点,每一步小 Z 以相等的概率随机选择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小 Z 到达 n n n 号顶点时游走结束,总分为所有获得的分数之和。

现在,请你对这 m m m 条边进行编号,使得小 Z 获得的总分的期望值最小。

数据范围: 2 ≤ n ≤ 500 2\le n\le500 2n500,保证图是一个简单无向连通图


solution

根据期望的线性性,我们可以先算出经过的边的期望,再分配标号。

但是边的期望不好算,我们可以转换一下:

E [ ( u , v ) ] = E [ u ] d e g u + E [ v ] d e g v E[(u,v)]=\frac{E[u]}{\mathrm{deg}_u}+\frac{E[v]}{\mathrm{deg}_v} E[(u,v)]=deguE[u]+degvE[v]

其中 d e g i \mathrm{deg}_i degi 表示 i i i 的度数。

那么,我们就把求边的期望转化成了求点的期望,那么有:

E [ u ] = ∑ u → v E [ v ] d e g v E[u]=\sum_{u\rightarrow v}\frac{E[v]}{\mathrm{deg}_v} E[u]=uvdegvE[v]

其中 u → v u\rightarrow v uv 表示 u , v u,v u,v 间有一条连边。

那么我们列出 n n n 个方程之后高斯消元即可解除所有的 E [ u ] E[u] E[u]

注意要两个点是特殊的:

  • 1 1 1 是起点,一开始就会有 1 1 1 的期望。
  • n n n 是终点,走到 n n n 就不会继续走了,因此不能在其他方程中列出。

求出所有边的期望后,根据排序不等式,给期望更大的边更小的编号得到的最后的期望是最小的。

时间复杂度 O ( n 3 ) O(n^3) O(n3)


code

#include<bits/stdc++.h>
using namespace std;
const int N=505,M=5e5+5;
int n,m,deg[N];
struct edges{int u,v;double P;}E[M];
bool operator<(const edges &p,const edges &q)  {return p.P>q.P;}
double a[N][N],X[N];
void Guass(){
	for(int i=1;i<=n;++i){
		int k=i;
		for(int j=i+1;j<=n;++j)
			if(fabs(a[j][i])>fabs(a[k][i]))  k=j;
		swap(a[i],a[k]);
		for(int j=i+1;j<=n;++j)
			for(int k=i+1;k<=n+1;++k)
				a[j][k]-=a[j][i]*a[i][k]/a[i][i];
	}
	for(int i=n;i>=1;--i){
		for(int j=i+1;j<=n;++j)
			a[i][n+1]-=X[j]*a[i][j];
		X[i]=a[i][n+1]/a[i][i];
	}
}
vector<int>e[N];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1,x,y;i<=m;++i){
		scanf("%d%d",&x,&y),E[i]=(edges){x,y};
		deg[x]++,deg[y]++,e[x].push_back(y),e[y].push_back(x);
	}
	for(int i=1;i<n;++i){
		a[i][i]=1,a[i][n+1]=0;
		for(int &to:e[i])  if(to!=n)  a[i][to]=-1.0/deg[to];
	}
	a[1][n+1]=1,a[n][n]=1;
	Guass();
	for(int i=1;i<=m;++i){
		int u=E[i].u,v=E[i].v;
		E[i].P=X[u]/deg[u]+X[v]/deg[v];
	}
	sort(E+1,E+m+1);
	double ans=0;
	for(int i=1;i<=m;++i)  ans+=E[i].P*i;
	printf("%.3lf\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值