bzoj 1415: [Noi2005]聪聪和可可(概率dp)

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/zzk_233/article/details/82937997

吐槽鬼体面。。到底问的是什么。。。其实问的不是时间,是步数的期望。

首先预处理一个dis数组,dis[x][y]表示从x到y的最短路步数因为边权为1,可以bfs,当然我写的spfa(我懒)。

从题目我们可以发现,zhx是一定会 被 吃了的,毕竟机器人走两步zhx走一步,所以只需考虑他们不断逼近的情况。

设f[x][y] 表示这一秒开始时,机器人在x,zhx在y时,机器人吃到zhx的期望天数,当x=y时, f[x][y]=0。

当dis[x][y]≤2时,f[x][y]=1,设w为x能到达的最接近y的点,设du[y] 为y能到达的点的个数,

设p为走一步或不走的概率,则p=1/(du[y]+1),设y下一个可能到 达的点为v,f[x][y] = (f[w][y]+Σf[w][v])*p+1。这一步可以递归求解。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
struct node
{
	int to;
	int nxt;
}edge[2005];
int head[1005];
int cnt = 1;
void init()
{
	memset(head,-1,sizeof(head));
}
void add(int from,int to)
{
	edge[cnt].to = to;
	edge[cnt].nxt = head[from];
	head[from] = cnt++;
}
int dis[1005][1005];
int used[1005][1005];
int choose[1005][1005];
double f[1005][1005];
int du[1005];
void spfa(int rt)
{
	dis[rt][rt] = 0;
	used[rt][rt] = 1;
	queue<int>M;
	M.push(rt);
	while(!M.empty())
	{
		int u = M.front();
		M.pop();
		for(int i = head[u];i != -1;i = edge[i].nxt)
		{
			int to = edge[i].to;
			if(dis[rt][to]>dis[rt][u]+1)
			{
				dis[rt][to] = dis[rt][u]+1;
				if(!used[rt][to])
				{
					used[rt][to] = 1;
					M.push(to);
				}
			}
		}
		used[rt][u] = 0;
	}
}
double gett(int x,int y)
{
	if(f[x][y] != -1.0)return f[x][y];
	if(x == y)return f[x][y] = 0.0;
	if(dis[x][y] <= 2)return f[x][y] = 1.0;
	f[x][y] = 0;
	double p = 1.0/(du[y]+1);
	int w = choose[choose[x][y]][y];
	for(int i = head[y];i != -1;i = edge[i].nxt)
	{
		int to = edge[i].to;
		f[x][y] += gett(w,to);
	}	
	f[x][y] += gett(w,y);
	f[x][y] *= p;
	f[x][y]++;
	return f[x][y];
}
int main()
{
	init();
	int n,e;
	scanf("%d%d",&n, &e);
	int c,m;
	scanf("%d%d", &c, &m);
	for(int i = 1;i <= e;i++)
	{
		int a,b;
		scanf("%d%d", &a, &b);
		add(a,b);
		add(b,a);
		du[a]++,du[b]++;
	}
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= n;j++)
		{
			f[i][j] = -1.0;
		}
	}
	memset(dis,0x3f,sizeof(dis));
	for(int i = 1;i <= n;i++)
	{
		spfa(i);
	}
	memset(choose,0x3f,sizeof(choose));
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= n;j++)
		{
			if(dis[i][j] == 0x3f3f3f3f)continue;
			for(int k = head[i];k != -1;k = edge[k].nxt)
			{
				int to = edge[k].to;
				if(dis[i][j] == dis[to][j]+1 && choose[i][j] > to)
				{
					choose[i][j] = to;
				}
			}
		}
	}
	printf("%.3lf",gett(c,m));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zzk_233/article/details/82937997