「NOI2005」聪聪和可可 题解
本文网址:https://www.cnblogs.com/zsc985246/p/16366661.html ,转载请注明出处。
题目大意
\(n\) 个点,\(m\) 条路的无向图,猫在 \(S\) 点,老鼠在 \(T\) 点,假设每个时间节点猫先走。猫每个时间节点可以靠近老鼠走两步(最短路),如果一步就可以抓到老鼠,就走一步,如果有多条最短路,选择节点标号小的一条;老鼠等概率地选择去向相邻的点或停留。
求猫捉到老鼠的期望时间(注意不是步数)。
思路
$ dp $ 求期望。
考虑 $ dis[i][j] $ 表示猫在 $ i $ 点,老鼠在 $ j $ 点时,猫与老鼠间的距离,用 $ bfs $ 求解。
用 $ dp $ 做,所以定义 $ f[i][j] $ 表示猫在 $ i $ 老鼠在 $ j $ 的期望步数,则:
-
$ i=j $ ,即 $ dis[i][j]=0 $ 直接可以抓到老鼠, $ f[i][j]=0 $ ;
-
$ dis[i][j] \le 2 $ ,即走一步就可以抓到老鼠, $ f[i][j]=1 $ ;
-
$ dis[i][j]>2 $ ,不能在一次选择中抓到老鼠,那么她抓到老鼠的期望就与老鼠所做的选择有关了。
因为 $ E(ax+by)=a \times E(x)+b \times E(y) $ ,所以:
$ f[i][j]= \frac{1}{in[j]+1} \times f[x][j] + \underset y \sum (\frac{1}{in[j]+1} \times f[x][y]) $
$ in[i] $ 表示 $ i $ 连接的路的条数, $ \frac{1}{in[j]+1} $ 表示老鼠行动的概率, $ x $ 表示猫下一步的位置, $ y $ 表示老鼠下一步的位置。
第一坨表示老鼠停留时的期望,第二坨表示老鼠走时的期望。
考虑到时间复杂度,使用记忆化搜索。
因此,代码出。
代码实现
#include<bits/stdc++.h>
#define ll int
const ll N=2020;
using namespace std;
ll n,m;
ll S,T;//猫和老鼠的起始点
ll cnt,fir[N],nxt[N],v[N];//前向星
ll in[N];//in[i]表示i连的边的条数
ll dis[N][N];//dis[i][j]表示猫在i点,老鼠在j点时,猫与老鼠间的距离
double f[N][N];//dp[i][j]表示猫在i老鼠在j的期望步数。
//不开double见祖宗!
void add(ll u1,ll v1){
v[++cnt]=v1;
nxt[cnt]=fir[u1];
fir[u1]=cnt;
}
void bfs(ll s){//bfs求距离,s表示起点
queue<ll>q;
q.push(s);
while(!q.empty()){
ll x=q.front();
q.pop();
for(ll i=fir[x];i;i=nxt[i]){
if(!dis[s][v[i]]&&v[i]!=s){
dis[s][v[i]]=dis[s][x]+1;
q.push(v[i]);
}
}
}
}
double dfs(ll s,ll t){//记忆化搜索,s表示猫的位置,t表示老鼠的位置
if(f[s][t])return f[s][t];
if(dis[s][t]==0)return 0;//直接可以抓到老鼠
if(dis[s][t]<=2)return 1;//走一步就可以抓到老鼠
f[s][t]=1;
ll k=N,tmp=s;//k表示最小编号,tmp表示猫的位置
//猫的行动
//走一步
for(ll i=fir[tmp];i;i=nxt[i]){
if(dis[t][v[i]]<dis[tmp][t]&&v[i]<k){//距离小且编号小
k=v[i];
}
}
tmp=k,k=N;
//再走一步
for(ll i=fir[tmp];i;i=nxt[i]){
if(dis[t][v[i]]<dis[tmp][t]&&v[i]<k){
k=v[i];
}
}
tmp=k;
//老鼠的行动
for(ll i=fir[t];i;i=nxt[i]){
f[s][t]+=1.0/(in[t]+1)*dfs(tmp,v[i]);//公式第二坨
}
f[s][t]+=1.0/(in[t]+1)*dfs(tmp,t);//公式第一坨
return f[s][t];
}
int main(){
scanf("%d%d",&n,&m);
scanf("%d%d",&S,&T);
for(ll i=1;i<=m;i++){
ll u1,v1;
scanf("%d%d",&u1,&v1);
add(u1,v1),add(v1,u1);
in[u1]++,in[v1]++;
}
for(ll i=1;i<=n;i++)bfs(i);
printf("%.3lf\n",dfs(S,T));
return 0;
}
尾声
如果你发现了问题,你可以直接回复这篇题解
如果你有更好的想法,也可以直接回复!

浙公网安备 33010602011771号