1. 程式人生 > >BZOJ1415 || 洛谷P4206 [NOI2005]聰聰與可可【期望DP&&記憶化搜尋】

BZOJ1415 || 洛谷P4206 [NOI2005]聰聰與可可【期望DP&&記憶化搜尋】

Time Limit: 10 Sec Memory Limit: 162 MB

Description

在這裡插入圖片描述

Input

資料的第1行為兩個整數N和E,以空格分隔,分別表示森林中的景點數和連線相鄰景點的路的條數。 第2行包含兩個整數C和M,以空格分隔,分別表示初始時聰聰和可可所在的景點的編號。 接下來E行,每行兩個整數,第i+2行的兩個整數Ai和Bi表示景點Ai和景點Bi之間有一條路。 所有的路都是無向的,即:如果能從A走到B,就可以從B走到A。 輸入保證任何兩個景點之間不會有多於一條路直接相連,且聰聰和可可之間必有路直接或間接的相連。

Output

輸出1個實數,四捨五入保留三位小數,表示平均多少個時間單位後聰聰會把可可吃掉。

題目分析

先預處理rem[u][v]rem[u][v]表示當前聰聰在uu,可可在vv時,聰聰下一個會到達的點 可以直接以每個點vv為起點跑最短路,並記錄令dis[u]dis[u]最小的上一個結點pre[u]pre[u] 那麼有rem[u][v]=pre[u]rem[u][v]=pre[u]

預處理完後的DP就比較好想了 dp[u][v]dp[u][v]表示當前聰聰在uu,可可在vv時,聰聰與可可相遇的期望步數 特別注意題目中 聰聰在一個時間段能走兩步! 於是邊界條件u==vu==vd

p[u][v]=0dp[u][v]=0 rem[u][v]==vrem[rem[u][v]][v]==vrem[u][v]==v\ ||\ rem[\ rem[u][v]\ ][v]==vdp[u][v]=1dp[u][v]=1

其餘情況下有(記t=rem[rem[u][v]][v]t=rem[\ rem[u][v]\ ][v]) dp[u][v]=DP(t,v)+DP(t,j)deg[v]+1+1dp[u][v]=\frac{DP(t,v)+\sum DP(t,j)}{deg[v]+1}+1

套上記搜即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
typedef double dd;

int read()
{
    int x=0,f=1;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}

const int maxn=1010;
int n,m,x,y;
struct node{int v,nxt;}E[maxn<<1];
int head[maxn],tot;
int d[maxn],vis[maxn],pre[maxn];
int rem[maxn][maxn],deg[maxn];
int judge[maxn][maxn];
dd dp[maxn][maxn];

void add(int u,int v)
{
	E[++tot].nxt=head[u];
	E[tot].v=v;
	head[u]=tot;
}

void SPFA(int s)
{
	memset(d,67,sizeof(d)); d[s]=0;
	queue<int> q; q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop(); vis[u]=0;
		for(int i=head[u];i;i=E[i].nxt)
		{
			int v=E[i].v;
			if(d[v]>d[u]+1)
			{
				d[v]=d[u]+1; pre[v]=u;
				if(!vis[v])q.push(v),vis[v]=1;
			}
			if(d[v]==d[u]+1)
			pre[v]=u<pre[v]?u:pre[v];
		}
	}
	for(int i=1;i<=n;++i) rem[i][s]=pre[i];
}

dd DP(int u,int v)
{
	if(judge[u][v]) return dp[u][v];
	judge[u][v]=1;
	if(u==v) return dp[u][v]=0;
	if(rem[u][v]==v||rem[rem[u][v]][v]==v) return dp[u][v]=1;//cout<<"hh"<<endl;
	
	int t=rem[rem[u][v]][v];
	dd res=DP(t,v),cnt=0;
	for(int i=head[v];i;i=E[i].nxt)
	res+=DP(t,E[i].v);
	return dp[u][v]=res/(deg[v]+1)+1;
}

int main()
{
    n=read();m=read(); x=read();y=read();
    for(int i=1;i<=m;++i)
    {
    	int u=read(),v=read(); 
		deg[u]++; deg[v]++;
    	add(u,v); add(v,u);
	}
	for(int i=1;i<=n;++i) SPFA(i);
	printf("%.3lf",DP(x,y));
	return 0;
}