●BZOJ 3143 [Hnoi2013]游走

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3143
题解:

期望dp,高斯消元
首先有这样一种贪心分配边的编号的方案:(然后我没想到,233)
我们按每一条边的期望经过次数去分配编号,
具体来说,就是期望经过次数越多的边,分配的编号越小,反之则编号越大。

然后问题转化为如何求一条边的期望经过次数。(把求边的期望转化为求点的期望)
我们定义cnt[i]表示i点的出度,dp[i]表示期望经过i点的次数。
然后对于一个边(u,v),期望经过该边的次数为dp[u]/cnt[u]+dp[v]/cnt[v].
特别的:当u或者v为N号点时,对边的期望贡献为0,因为到了N点就结束了。
所以现在需要求出dp[i].
由全期望公式$$dp[i]=\sum_{j->i}dp[j]/cnt[j]$$
特别的:
1.j!=N,因为到达N点就已经结束游戏。
2.当i==1时,dp[i]还要多加一个数值1,因为初始是就期望直接经过了1次。
显然这个DP存在环,所以高斯消元解出dp值,然后再求出每一条边的期望经过次数,贪心地去编号即可。

注:高斯消元判断系数是否为0时,要用到eps,否则可能因为精度问题而出错。

代码:

#include<bits/stdc++.h>
#define MAXN 505
using namespace std;
const double eps=1e-7;
struct EDGE{
	int u,v; double exp;
	bool operator < (const EDGE &rtm) const{
		return exp>rtm.exp;
	}
}E[MAXN*MAXN];
double a[MAXN][MAXN],dp[MAXN],ans;
double *A[MAXN];
bool Edge[MAXN][MAXN];
int cnt[MAXN];
int N,M;
int dcmp(double x){
	if(fabs(x)<=eps) return 0;
	return x>0?1:-1;
}
void Gausselimination(int pos,int i){
	if(pos==N+1||i==N+1) return;
	for(int j=pos;j<=N;j++) if(dcmp(A[j][i])!=0){
		swap(A[pos],A[j]); break;
	}
	if(dcmp(A[pos][i])!=0){
		for(int j=pos+1;j<=N;j++){
			double k=A[j][i]/A[pos][i];
			for(int l=i;l<=N+1;l++)
				A[j][l]-=A[pos][l]*k;
		}
	}
	Gausselimination(pos+(dcmp(A[pos][i])!=0),i+1);
	if(dcmp(A[pos][i])!=0){
		for(int l=i+1;l<=N;l++)
			dp[i]+=A[pos][l]*dp[l];
		dp[i]=A[pos][N+1]-dp[i];
		dp[i]=dp[i]/A[pos][i];
	}
}
void buildequation(){
	for(int i=1;i<=N;i++){
		a[i][i]=-1;
		if(i==1) a[i][N+1]=-1;
		for(int j=1;j<N;j++){
			if(!Edge[j][i]) continue;
			a[i][j]=1.0/cnt[j];
		}
	}
	for(int i=1;i<=N;i++) A[i]=a[i];
}
int main(){
	scanf("%d%d",&N,&M);
	for(int i=1,u,v;i<=M;i++){
		scanf("%d%d",&u,&v);
		E[i].u=u; E[i].v=v;
		Edge[u][v]=Edge[v][u]=1;
		cnt[u]++; cnt[v]++;
	}
	buildequation();
	Gausselimination(1,1);
	for(int i=1,u,v;i<=M;i++){
		u=E[i].u; v=E[i].v;
		E[i].exp=(u!=N?dp[u]/cnt[u]:0)+(v!=N?dp[v]/cnt[v]:0);
	}
	sort(E+1,E+M+1);
	for(int i=1;i<=M;i++)
		ans+=E[i].exp*i;
	printf("%.3lf\n",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/zj75211/p/8541955.html

时间: 2024-11-10 16:17:47

●BZOJ 3143 [Hnoi2013]游走的相关文章

BZOJ 3143: [Hnoi2013]游走( 高斯消元 )

我一开始的想法是设f(x)表示点x到N路径的期望长度, 那么f(u) = (∑f(v)+w(u,v)) / degreeu, f(N)=0, 我们代入入消元应该可以得到f(1)关于各条边长的关系式f(1)=∑we..然后贪心, 按照他们的系数来给边权...但是不会实现..但是我感觉是可行的..PoPoQQQ题解:http://blog.csdn.net/PoPoQQQ/article/details/42234607 ---------------------------------------

BZOJ 3143 HNOI2013 游走 高斯消元 期望

这道题是我第一次使用高斯消元解决期望类的问题,首发A了,感觉爽爽的.... 中文题目,就不翻大意了,直接给原题: 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数.当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和. 现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小. 输出最小的总分期望值. Solution: 这题贪心很明显

[BZOJ 3143][Hnoi2013]游走(高斯消元+期望)

Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数.当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和. 现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小. Solution 对于点u(u≠1):到达u的概率 f[u]=∑f[v]/d[v] (Edges(u,v)) 而f[1]=∑f[v]/d[v]+1

[BZOJ 3143][HNOI2013]游走(数学期望)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3143 分析: 易得如果知道了每条边经过的数学期望,那就可以贪心着按每条边的期望的大小赋值,所以问题就是如何求每条边的期望. 直接求没办法求的,可以先求出每个点经过的期望. 易得f[i]=∑f[j]/d[j] j->i有边 特殊的,对于起点,因为刚开始就在,所以应该是f[1]=1+∑f[j]/d[j]:对于终点,到了终点后不能再到其他节点,所以对其他边并没有贡献,所以f[n]=0 然后

bzoj 3143: [Hnoi2013]游走

高斯消元 对于边可能很多,那我们计录点的期望次数就行了. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #include<vector> 9 #define M 1009 10 #

BZOJ 3143 HNOI2013 游走 期望DP+高斯消元

题目大意:给定一个无向连通图,我们需要给每条边附一个1~m的不重复的权值,使1到n的期望权值和最小 首先贪心思想是求出每条边的期望经过次数 然后对期望值最小的边附加m的权值,第二小的边附加m-1的权值,以此类推. 令f[i]为第i个点的期望经过次数 那么每条边的期望经过次数就是f[x]/d[x]+f[y]/d[y] 其中d[x]表示x的度数 那么显然有: f[1]=1+Σ[1->j]f[j]/d[j] f[i]=Σ[i->j]f[j]/d[j] (2<=i<=n-1) 其中f[n]

bzoj 3143 [Hnoi2013]游走【高斯消元+dp】

参考:http://blog.csdn.net/vmurder/article/details/44542575 和2337有点像 设点u的经过期望(还是概率啊我也分不清,以下都分不清)为\( x[u] \) ,度为 \( in[u] \),边\( (u,v) \) 的经过期望为 \( \frac{x[u]}{in[u]}+\frac{x[v]}{in[v]} \) 那么转换为求每个点的经过期望,\( x[u]=\sum_{v}^{v\subset son(u)}\frac{x[v]}{in[v

bzoj 3143 随机游走

题意: 给一个简单无向图,一个人从1号节点开始随机游走(即以相同概率走向与它相邻的点),走到n便停止,问每条边期望走的步数. 首先求出每个点期望走到的次数,每条边自然是从它的两个端点走来. 1 /************************************************************** 2 Problem: 3143 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:736 ms 7 Memory:

【BZOJ】3143: [Hnoi2013]游走 期望+高斯消元

[题意]给定n个点m条边的无向连通图,每条路径的代价是其编号大小,每个点等概率往周围走,要求给所有边编号,使得从1到n的期望总分最小(求该总分).n<=500. [算法]期望+高斯消元 [题解]显然,应使经过次数越多的边编号越小,问题转化为求每条边的期望经过次数. 边数太多,容易知道f(u,v)=f(u)/out(u)+f(v)/out(v),所以转化为求每个点的期望经过次数,这就是驱逐猪猡了. 设f[x]表示点x的期望经过次数,根据全期望公式(讨论"经过"的问题不能依赖于下一步