一、题目
题目:
n n n个点, m m m条边的联通无向图,边的权值从 1 1 1到 m m m,一开始在1号点,每次等概率走向当前点的邻接点。问怎么样给边赋值,使得走到 n n n号点时期望走过的边权和最小。
数据范围:
2 ≤ N ≤ 500 2\leq N\leq 500 2≤N≤500
二、解法
UPD:2020/4/6 \text{UPD:2020/4/6} UPD:2020/4/6,发现以前写的博客有问题,故来重做一波。
首先我们想求出每条边出现的期望次数,这样方便编号,求出每条边的出现次数可以转化为求出点的期望出现次数
E
(
i
)
E(i)
E(i),这样一条边
(
u
,
v
)
(u,v)
(u,v)就可以表示为:
E
(
u
)
d
e
g
[
u
]
+
E
[
v
]
d
e
g
[
v
]
\frac{E(u)}{deg[u]}+\frac{E[v]}{deg[v]}
deg[u]E(u)+deg[v]E[v]如何求出
E
(
i
)
E(i)
E(i)呢,一个显然的思路是高斯消元,数据范围也允许我们这样做,先列出一串柿子:
E
(
i
)
=
{
∑
(
i
,
j
)
∈
e
d
g
e
,
j
≠
n
E
(
j
)
d
e
g
[
j
]
+
1
i
=
1
∑
(
i
,
j
)
∈
e
d
g
e
,
j
≠
n
E
(
j
)
d
e
g
[
j
]
1
<
i
<
n
E(i)=\begin{cases}\sum_{(i,j)\in edge,j\not=n}\frac{E(j)}{deg[j]}+1&i=1\\\sum_{(i,j)\in edge,j\not=n}\frac{E(j)}{deg[j]}&1<i<n\end{cases}
E(i)={∑(i,j)∈edge,j=ndeg[j]E(j)+1∑(i,j)∈edge,j=ndeg[j]E(j)i=11<i<n然后移个项就可做了,算出边期望之后从大到小排序,然后
1
1
1到
m
m
m挨个赋值即可,时间复杂度
O
(
n
3
)
O(n^3)
O(n3)
#include <cstdio>
#include <iostream>
#include <algorithm>
#define eps 1e-7
using namespace std;
const int MAXN = 505;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m;
bool b[MAXN][MAXN];
double a[MAXN][MAXN],q[MAXN*MAXN],deg[MAXN];
struct edge
{
int u,v;
}e[MAXN*MAXN];
bool cmp(double a,double b)
{
return a>b;
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
b[u][v]=b[v][u]=1;
e[i]=edge{u,v};
deg[u]+=1.0;deg[v]+=1.0;
}
a[1][n]=1.0;
for(int i=1;i<n;i++)
{
a[i][i]=1.0;
for(int j=1;j<n;j++)
if(b[i][j])
a[i][j]=-1.0/deg[j];
}
for(int i=1;i<n;i++)
{
int Max=i;
for(int r=i+1;r<n;r++)
if(a[r][i]-a[Max][i]>eps)
Max=r;
if(i^Max)swap(a[i],a[Max]);
for(int j=n;j>=i;j--)
a[i][j]/=a[i][i];
for(int j=1;j<n;j++)
{
if(i==j || !a[j][i]) continue;
double tmp=a[j][i]/a[i][i];
for(int k=i+1;k<=n;k++)
a[j][k]-=a[i][k]*tmp;
a[j][i]=0;
}
}
for(int i=1;i<=m;i++)
{
int u=e[i].u,v=e[i].v;
if(u^n) q[i]+=a[u][n]*(1.0/deg[u]);
if(v^n) q[i]+=a[v][n]*(1.0/deg[v]);
}
sort(q+1,q+1+m,cmp);
double ans=0;
for(int i=1;i<=m;i++)
ans+=q[i]*i;
printf("%.3lf",ans);
return 0;
}