[ BAPC 2016 ] Lost In The Woods 后效性处理(列方程)+高斯消元

题目链接: Lost In The Woods

题意

给你n个点m条边,每走过一条边的时间为1分钟,让你从0出发,问到编号为(n-1)的点所需的时间期望为多少?

题解

由于对走法没有限制,会出现来回走的情况,一开始用bfs模拟发现耗时大,并且答案误差较大,后来经大佬指点,才明白此类带有后效性问题,可以通过列方程然后高斯消元求解。

我们可以逆向考虑,设dp[x]为x点到(n-1)点的时间期望。
我们很容易发现dp[n-1]=0
并且我们可以列出一个方程:

d p [ x ] = ∑ k ∈ ( 所 有 与 x 相 连 的 点 ) d p [ k ] + 1 s u m {dp[x]=\sum_{k\in(所有与x相连的点)}\frac{dp[k]+1}{sum}} dp[x]=k(x)sumdp[k]+1 (sum为所有与x相连的边数。)

(n-1)个方程(n-1)个未知数,我们可以通过高斯消元求出从0出发到(n-1)点的期望。

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e6+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

vector<int> g[25];
double A[25][25];

void guess_elimination(int n)
{
    
    
	for(int i=1;i<=n;i++)
	{
    
    
		//选择一行r并与第i行交换
		int r=i;
		for(int j=i+1;j<=n;j++)
			if(fabs(A[j][i]) > fabs(A[r][i])) r=j;
		if(r != i) for(int j=1;j <= n+1;j++) swap(A[r][j],A[i][j]);
		
		//与i+1~n进行消元       
		for(int k=i+1;k<=n;k++)
			for(int j=n+1;j>=i;j--)
				A[k][j] -= A[k][i]/A[i][i] *A[i][j];
	}
	
	//回代
	for(int i=n;i>=1;i--)
	{
    
    
		for(int j=i+1;j<=n;j++) 
			A[i][n+1] -= A[j][n+1] * A[i][j];
		A[i][n+1] /= A[i][i];
	}
}

int main()
{
    
    
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
    
    
		int x,y; scanf("%d%d",&x,&y);
		x++,y++;
		g[x].pb(y);
		g[y].pb(x);
	}
	for(int i=1;i<n;i++)
	{
    
    
		int sum=g[i].size();
		A[i][i]=sum;
		A[i][n+1]=sum;
		for(int j=0;j<sum;j++)
		{
    
    
			int v=g[i][j];
			A[i][v]= -1.0;
		}
	}
	A[n][n] = 521.0;
	guess_elimination(n);
	printf("%.6f\n",A[1][n+1]);
}

猜你喜欢

转载自blog.csdn.net/weixin_44235989/article/details/108074914
今日推荐