NOI2005 聪聪和可可

题目大意:给定一张图,A的起始位置和B的启示位置,A在一个时间点内移动两格,B移动一格。且A移动方向始终靠近B,而B等概率的移动到与它联通的节点和所在位置。求当A和B处在同一位置时平均步数为几步。


题目分析:一道求期望的题目。可以先预处理出每个节点向另外节点方向走一步时候的位置。定义状态dp[i][j]表示为B在i,A在j时候的步数期望。

显然对于同一位置即dp[i][i]=0。 如果在一个单位时间内之内可以到达那么期望为1;

设A一开始在j处,一个单位时间内到达Z点,则dp[i][j]=1+(dp[i][Z]+sigma(dp[k][Z]))/(g[i]+1) i与k相连。g[i]表示有几个点与i相连。


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
#include<cassert>
#include<climits>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a))
#define MEMI(a) memset(a,127,sizeof(a))
#define MEMi(a) memset(a,128,sizeof(a))
#define INF (2139062143)
#define phiF (1000000006)
#define MAXN (1000000+10)
typedef long long LL;

struct info{
	int to,next;
}e[2005];

int first[2005],g[2005],dist[2005],tot,n,m,s,en,q[1005],a[1005][1005],x,y;
bool flag[2005];
double dp[1005][1005];

inline void add(int x,int y){
	e[++tot].to=y;
	e[tot].next=first[x];
	first[x]=tot;
	++g[x];
}

inline void bfs(int x){
	For (i,n)
	 flag[i]=1,dist[i]=0;
	int h=1,t=1;
	flag[x]=0;
	q[1]=x;
	for (;h<=t;h++){
		for (int i=first[q[h]];i;i=e[i].next){
		  int v=e[i].to;
		  if (flag[v]){
		  	 flag[v]=0;
		  	 dist[v]=dist[q[h]]+1;
		  	 t++;
		  	 q[t]=v;
		  	 a[v][x]=q[h];
		  }else if (dist[v]==dist[q[h]]+1 && q[h]<a[v][x])	a[v][x]=q[h];		
	    }
	}
}

inline double dfs(int x,int y){
	if (dp[x][y]>-1) return dp[x][y];
	if (x==y) return dp[x][y]=0;
	int z=a[a[x][y]][y];
	if (z==y||a[x][y]==y) return dp[x][y]=1;
	double tmp=1/(g[y]+1);
	double sum=dfs(z,y);
    for (int i=first[y];i;i=e[i].next)
        sum+=dfs(z,e[i].to);
    return dp[x][y]=sum/(g[y]+1)+1; 
}



int main(){
	scanf("%d%d%d%d",&n,&m,&s,&en);
	For (i,m) {
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	
	For (i,n) bfs(i);
	For (i,n)
	 For (j,n)
	   dp[i][j]=-1;
	printf("%.3f",dfs(s,en));   
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值