zoukankan      html  css  js  c++  java
  • 【YBTOJ】【Luogu P3232】[HNOI2013]游走

    链接:

    题目

    博客园

    题目描述:

    给定一个 (n) 个点 (m) 条边的无向连通图,顶点从 (1) 编号到 (n),边从 (1) 编号到 (m)

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

    (2leq n leq 500,1 leq m leq 125000)

    正文:

    边的数量太大,所以我们不能以直接求边的期望经过次数。那我们就求每个点的。设 (f_i) 表示第 (i) 个点的期望经过次数。那么第 (i) 条边的期望经过次数 (g_i) 就很好求了:

    [g_i=frac{f_u}{deg_u}+frac{f_v}{deg_v} ]

    其中 (deg_i) 表示第 (i) 个点的度数。


    现在我们的问题是如何求 (f_i) 了。

    容易得到:

    [f_i=sum_{(i,j)in E,j ot=n}frac{f_j}{deg_u}+(i==1) ]

    如果我们直接 DFS,肯定是过不了的。可以用高斯消元。

    首先 (1) 号点到 (n) 点的概率肯定是 (1),其次是点 (i) 的期望次数减去其它点转移过来的期望次数肯定是 (0)

    因为到 (n) 停止游走,不能考虑 (n),这样就能构成 (n-1) 个线性方程组,可以开搞高消了。

    最后将 (g_i) 倒序排序,就能得到答案了。

    代码:

    int n, m;
    int deg[N];
    double f[N], a[N][N], g[M], ans;
    
    struct edge
    {
    	int from, to, nxt;
    }e[M << 1];
    int head[N], tot;
    
    void add (int u, int v)
    {
    	e[++tot] = (edge){u, v, head[u]}, head[u] = tot;
    }
    
    void Gauss(int n)
    {
    	for (int i = 1; i <= n; i++)
    	{
    		int mxi = i;
    		for (int j = i + 1; j <= n; j++)
    			if(fabs(a[mxi][i]) < fabs(a[j][i])) mxi = j;
    		swap(a[mxi], a[i]);
    		double inv = a[i][i];
    		for (int j = i; j <= n + 1; j++)
    			a[i][j] /= inv;
    		for (int j = i + 1; j <= n; j++)
    		{
    			inv = a[j][i];
    			for (int k = i; k <= n + 1; k++)
    				a[j][k] -= a[i][k] * inv;
    		}
    	} 
    	f[n] = a[n][n + 1];
    	for (int i = n - 1; i; --i)
    	{
    		for (int j = i + 1; j <= n; ++j)
    			a[i][n + 1] -= f[j] * a[i][j];
    		f[i] = a[i][n + 1] / a[i][i];
    	}
    }
    
    int main()
    {
    	scanf ("%d%d", &n, &m);
    	for (int i = 1; i <= m; i++)
    	{
    		int x, y;
    		scanf ("%d%d", &x, &y);
    		add (x, y), add(y, x);
    		deg[x]++, deg[y]++;
    	}
    	
    	for (int i = 1; i < n; i++)
    	{
    		a[i][i] = 1.0;
    		for (int j = head[i]; j; j = e[j].nxt)
    		{
    			int v = e[j].to;
    			if (v != n) a[i][v] -= 1.0 / deg[v];
    		}
    	}
    	a[1][n] = 1;
    	
    	Gauss (n - 1);
    	
    	for (int i = 1; i <= m; i++)
    		g[i] = f[e[i<<1].from] / deg[e[i<<1].from] + f[e[i<<1].to] / deg[e[i<<1].to];
    	sort (g + 1, g + 1 + m);
    	for (int i = 1; i <= m; i++)
    		ans += g[i] * (m - i + 1.0);
    	printf ("%.3lf", ans);
    	return 0;
    }
    
  • 相关阅读:
    vue-loader介绍和单页组件介绍
    webpack的插件 http-webpack-plugin。 webpack-dev-server
    webpack的介绍
    Axios 的基本使用
    如何使用 re模块的, spilt.
    为 JS 的字符串,添加一个 format 的功能。
    另一种分页器 不依赖Paginator模块的方法
    Socket初识
    网络协议
    双下方法补充以及异常处理
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14252975.html
Copyright © 2011-2022 走看看