[NOI2005]聪聪和可可

###概率与期望
首先还是建边,双向边,之后记录每一个点的出度,之后可以用\(spfa\)或者是\(dijkstra\)来计算出每个点之间的最短距离,每个猫都 绝 顶 聪 明 ,故他们会计算出来最短路来转移,但是我们计算最短路的目的并不是单纯的最短路,而是为了计算一个 miaomiao(四声)的数组:\(nxt\)数组。\(nxt_{i,j}\)就表示\(cat\)\(i\),然后\(mouse\)\(j\),之后 绝 顶 聪 明\(cat\)君所要走的下一步路。

有了 niubi\(nxt\)数组,我们就可一开始期望转移了,根据题目中所给的计算式可以得到(\(u\)代表\(cat\)君在的位置,\(v\)代表\(mouse\)君在的位置,然后\(cat\)君一定是想要去抓\(mouse\)君,\(firset_{step}\)代表\(cat\)君第一步到达的位置,\(second_{step}\)代表\(cat\)君第二部所要到达的位置):

\[case_1 : if(u == v)return 0; \]

\[case_2 : if(first_{step} == v or second_{step} == v) return 1; \]

如果都不是这两种情况,就考虑转移:

\[case_3 : f_{u,v} += (dfs(second_{step},v) + 1) / (p_i + 1) \]

所以\(code\):

#include<queue>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x7f7f7f7f
#define debug cout<<"debug"<<endl
namespace xin_io
{
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	char buf[1<<20],*p1 = buf,*p2 = buf;
	inline void openfile() {freopen("t.txt","r",stdin);}
	inline void outfile()  {freopen("o.txt","w",stdout);}
	inline int get()
	{
		int s = 0,f = 1;
		register char ch = gc();
		while(!isdigit(ch))
		{
			if(ch == '-') f = -1;
			ch = gc();
		}
		while(isdigit(ch))
		{
			s = s * 10 + ch - '0';
			ch = gc();
		}
		return  s * f;
	}
}
using namespace xin_io;
static const int maxn = 1e3+10;
namespace xin
{
	#define m(n,num) memset(n,num,sizeof n)
	int n,e,c,m;
	class xin_edge
	{
		public:
			int next;
			int ver;
	}edge[maxn<<1];
	int head[maxn<<1],zhi = 0;
	inline void add(int x,int y)
	{
		edge[++zhi].ver = y;  edge[zhi].next = head[x]; head[x] = zhi;
	}
	double f[maxn][maxn];
	bool mark[maxn][maxn];
	int p[maxn];
	int nxt[maxn][maxn];
	int dis[maxn];
	bool vis[maxn];
	inline void spfa(int st)
	{
		queue < int > q;
		m(vis,0); m(dis,127);
		q.push(st); vis[st] = true;
		while(q.size())
		{
			register int x = q.front(); q.pop(); vis[x] = false;
			dis[st] = 0;
			for(register int i=head[x];i;i=edge[i].next)
			{
				register int y = edge[i].ver;
				// cout<<"y = "<<y<<endl;
				// cout<<dis[y]<<endl;
				if(dis[y] > dis[x] + 1)
				{
					dis[y] = dis[x] + 1;
					// cout<<"y = "<<y<<" dis[y] = "<<dis[y]<<endl;
					if(!vis[y])
						q.push(y),vis[y] = true;
				}
			}
		}
		for(register int i=1;i<=n;++i) 
			if(i != st)
			{
				register int x = i;
				int minn = INF;
				for(register int i=head[x];i;i=edge[i].next)
				{
					register int y = edge[i].ver;
					if(dis[y] < minn)
						minn = dis[y],nxt[x][st] = y;
					else if(dis[y] == minn and y < nxt[x][st])
						nxt[x][st] = y;
				}
			}
	}
	double dfs(int u,int v)
	{
		int first = nxt[u][v],second = nxt[first][v];
		if(mark[u][v]) return f[u][v];
		if(u == v) return 0.0;
		if(first == v or second == v) return 1.0;
		for(register int i=head[v];i;i=edge[i].next)
		{
			register int y = edge[i].ver;
			f[u][v] += (dfs(second,y) + 1.0) / (1.0 * (p[v] + 1));
		}
		mark[u][v] = true;
		f[u][v] += (dfs(second,v) + 1.0) / (1.0 * (p[v] + 1));
		return f[u][v];
	}
	inline short main()
	{
	#ifndef ONLINE_JUDGE
		openfile(); outfile();
	#endif
		n = get(); e = get(); c = get(); m = get();
		for(register int i=1;i<=e;++i)
		{
			register int x = get(),y = get();
			add(x,y); add(y,x);
			p[x]++; p[y]++;
		}
		for(register int i=1;i<=n;++i)
			spfa(i);
		// for(register int i=1;i<=n;++i)
		// 	for(register int j=1;j<=n;++j)
		// 		cout<<"i = "<<i<<" j = "<<j<<" nxt[i][j] = "<<nxt[i][j]<<endl;
		printf("%.3lf\n",dfs(c,m));
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-05-22 18:55  NP2Z  阅读(46)  评论(0编辑  收藏  举报