P3232 [HNOI2013 / JSOI2013] 游走 解题思路梳理

前言

  • 注意!本文不是题解,仅仅是msjing为了整理思路写的,且msjing不想再另搞一个分区了所以扔题解里了,以后写得多了再整理,咕咕咕,请前往正规题解处查看题解

solve前(?)

  • 给一张无向图,一人随机虾极霸游走,给每个点编号,让总期望最小
  • 好提莫难搞啊啊啊啊啊啊提莫没有招惹任何人
  • 好吧有滚木个思路所以看看题解吧
  • 注:msjing看到是这篇/bx/bx/bx

solve?

  • 想让期望最小,贪心地想,让走的多的边编号小就是正确的
  • 问题来到:如何统计边的期望
  • \(g_i\) 为边 \(i\) 经过期望次数,我们发现这个与这个边的两端有关,那么我们有柿子
$g_{x,y} = \dfrac{f_x}{d_x} + \dfrac{f_y}{d_y}$
  • 其中,\(f_x , f_y\) 表示 \(x,y\) 的经过期望次数;\(d_x,d_y\) 表示 \(x,y\) 的度

  • 我们来理解一下,对于一次到达 \(x\) 并且走 \(x \to y\) 这条边的概率是 \(\frac{1}{d_x}\),所以乘上 \(f_x\),由于可以从 \(x\)\(y\) 到达这条边,所以是加和

  • 下一步,问题转化为:求点经过期望次数即 \(f_i\)

  • 仍然按上边定义,考虑 \(f_i\) 的受影响范围

  • 令要求的点为 \(x\),注意到与 \(x\) 有关的点就是 \(x\) 可以到的所有点,那么我们把他们全统计起来,有

$f_x = \sum\limits_{i=1}^{k}{\dfrac{f_i}{d_i}}$
  • 其中,\(k\) 是与 \(x\) 相连的所有点的个数

  • 我们再理解一下,我们已经知道每个点都和与它联通的节点有关,同上到一个点的概率为 \(\frac{1}{d_i}\),同上得到柿子

  • 但是还是要有注意的,共两点

    1. \(1\) 个点认为走过了,所以 \(f_1 = 1+\sum\limits{\frac{f_i}{d_i}}\)
    2. \(n\) 个点就要停了,所以直接 \(f_n = 0\)
  • 我们发现所有柿子加起来是 \(n-1\)\(n-1\) 元一次方程组,掏出 \(\mathscr{gaussjordan}\) 消元法,直接搞一下

代码实现

  • 有几个关于上述的实现
    1. 由于我们\(n\) 踢飞了不计算 \(n\),所以把 \(n-1\) 即可,但是要注意需要用 \(n\) 的时候要加回来
    2. 关于消完元的排序,就是贪心了
    3. 输入的边要记录一下后面要用
  • 注意数组的大小,msjing已经飞起来了
  • 代码就随便给了,没啥的,高斯消元就是板板板
点击查看代码
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=510,maxm=125010,eps=1e-8;
long long read() {long long x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch-'0');ch=getchar();}return x*f;}
int n,m;
int x[maxm],y[maxm],h[maxm<<1],to[maxm<<1],nxt[maxm<<1],tot,d[maxm];
void add(int x,int y) {tot++;to[tot]=y;nxt[tot]=h[x];h[x]=tot;}
double a[maxn][maxn],g[maxm],ans;
struct g_j
{
	void gauss_jordan()
	{
		for (int i=1;i<=n;i++)
		{
			int r=i;
			for (int j=i;j<=n;j++) if (fabs(a[j][i])>eps) {r=j;break;}
			if (r!=i) swap(a[r],a[i]);
			if(fabs(a[i][i])<eps) continue;
			for (int j=1;j<=n;j++)
			{
				if (j == i) continue;
				double t=a[j][i]/a[i][i];
				for (int k=i;k<=n+1;k++) a[j][k]-=t*a[i][k];
			}
		}
		for (int i=1;i<=n;i++) a[i][n+1]/=a[i][i];
	}
}G;
int main()
{
	n=read()-1,m=read();for (int i=1;i<=m;i++) x[i]=read(),y[i]=read(),add(x[i],y[i]),add(y[i],x[i]),d[x[i]]++,d[y[i]]++;
	a[1][n+1]=-1;
	for (int i=1;i<=n;i++)
	{
		a[i][i]=-1;
		for (int j=h[i];j;j=nxt[j])
		{
			int y=to[j];
			if (y!=n+1) a[i][y]=1.0/d[y];
		}
	}
	G.gauss_jordan();
	for (int i=1;i<=m;i++) g[i]=a[x[i]][n+1]/d[x[i]]+a[y[i]][n+1]/d[y[i]];
	sort(g+1,g+1+m);
	for (int i=1;i<=m;i++) ans+=g[i]*(m-i+1);
	printf("%.3lf\n",ans);
	return 0;
}

后话

  • 这是第114篇文了如果你数了数发现不够那就是msjing大手发力了哼哼哼哼哼哈啊啊啊啊啊啊,哈啊啊啊啊啊啊,啊啊啊啊啊啊啊,啊啊啊啊啊啊啊
  • 附图一张

9vejsduz

  • msjing要开始挑战随机游走

  • 这里是26.7.9的msjing,昨天写完随机游走,大概理解了

posted @ 2026-07-08 20:17  msjing  阅读(13)  评论(0)    收藏  举报