您的位置:首页 > 其它

【HNOI2013】游走

2016-03-21 21:02 295 查看

Description

给出一张n个点,m条边的无向连通图。有一个人从点1开始随机游走,到点n结束。他每走过一条边就会得到其编号的分数。(可以重复走而重复得分)。现在让你安排每条边的编号,让他的得分期望值最小。求这个最小值。

n<=500

Solution

我们发现只要求出每条边的期望经过次数,然后从大到小排序,依次编号,就一定是最小值了。(即期望大的编号要小)

但是,每条边的期望经过次数要怎么求呢?

这个东西非常麻烦,于是我们可以另辟巧径。

如果我们求出了每个点的期望经过次数?

那么每条边的期望经过次数ei就等于pxdx+pydy

pi为每个点的期望经过次数,di为每个点的出度。

这个很显然…

那么怎么求呢?

高斯消元!!

对于每个非1非n的点,pi=∑i−>jpjdj

1点因为一开始就在,所以要加1。

n点应该只有1,但是应为要避免它对其它点的影响,就变成0了。(因为走到n就走不出来了)

然后这道题就完美解决了!

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 505
#define db double
using namespace std;
struct note{
db a
,b;
}matrix
;
int l,n,m,t[N*N],next[N*N],last
,c
,d
,bz
,x[N*N],y[N*N];
db an
,e[N*N],ans;
void add(int x,int y) {
t[++l]=y;c[x]++;next[l]=last[x];last[x]=l;
}
void gauss() {
fo(i,1,n-1) {
fo(j,i+1,n) if (abs(matrix[j].a[i])>abs(matrix[i].a[i]))
swap(matrix[i],matrix[j]);
fo(j,i+1,n) {
db f=matrix[j].a[i]/matrix[i].a[i];
fo(k,i,n) matrix[j].a[k]=matrix[i].a[k]*f-matrix[j].a[k];
matrix[j].b=matrix[i].b*f-matrix[j].b;
}
}
fd(i,n,2) {
fo(j,1,i-1) {
db f=matrix[j].a[i]/matrix[i].a[i];
fo(k,j,n) matrix[j].a[k]=matrix[i].a[k]*f-matrix[j].a[k];
matrix[j].b=matrix[i].b*f-matrix[j].b;
}
}
fo(i,1,n) an[i]=matrix[i].b/matrix[i].a[i];
}
int main() {
scanf("%d%d",&n,&m);
fo(i,1,m) scanf("%d%d",&x[i],&y[i]),add(x[i],y[i]),add(y[i],x[i]);
int i=0,j=1;d[1]=1;bz[1]=1;
matrix
.a
=matrix[1].a[1]=matrix[1].b=1;
fo(i,1,n-1) {
matrix[i].a[i]=1;
rep(j,i) matrix[i].a[t[j]]=-1.0/c[t[j]];
}
gauss();
fo(i,1,m) e[i]=an[x[i]]/c[x[i]]+an[y[i]]/c[y[i]];
sort(e+1,e+m+1);
fo(i,1,m) ans=(ans+e[i]*(m-i+1));
printf("%.3lf",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: