[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();}