BZOJ1415 聪聪和可可
期望Dp
题解:
设 f[i][j] 表示聪聪在点i,可可在点j时的期望步数。
- i==j时, f[i][j]=0
- i按找要求走一步或两步能走到j时, f[i][j]=1
- 否则:
f[i][j]=f[i′][j]+1+∑(f[i′][j′]+1)du[j]+1
i’是i按照要求走两步后的点,j’是与j相连的点。
对了多说一句,它满足无后效性,就是两点之间的距离会越来越近。记忆化搜索即可。
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define MP make_pair
using namespace std;
const int N = 1005;
int n,m,du[N],path[N][N];
double f[N][N];
bool vis[N]; int dis[N][N];
struct Edge{
int to,next;
} e[N*2];
int head[N], ec;
void add(int a,int b){
ec++; e[ec].to=b; e[ec].next=head[a]; head[a]=ec;
}
void bfs(int S){
memset(vis,false,sizeof(vis));
queue<int> q; vis[S]=true; dis[S][S]=0; q.push(S);
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(!vis[v]){
vis[v]=true; dis[S][v]=dis[S][u]+1; q.push(v);
}
}
}
}
double dp(int i,int j){
double &ans=f[i][j];
if(ans>-0.1) return ans; //ans>=0
if(i==j) return ans=0;
int ii=path[i][j]; if(ii==j) return ans=1;
ii=path[ii][j]; if(ii==j) return ans=1;
ans=0; ans+=(dp(ii,j)+1)/(du[j]+1);
for(int tp=head[j];tp;tp=e[tp].next){
int jj=e[tp].to;
ans+=(dp(ii,jj)+1)/(du[j]+1);
}
return ans;
}
int main(){
freopen("a.in","r",stdin);
int cc,kk,a,b;
scanf("%d%d%d%d",&n,&m,&cc,&kk);
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
add(a,b); add(b,a);
du[a]++; du[b]++;
}
for(int i=1;i<=n;i++) bfs(i);
for(int u=1;u<=n;u++){
for(int v=1;v<=n;v++){
path[u][v]=u;
for(int i=head[u];i;i=e[i].next){
int p=e[i].to;
if(dis[p][v]<dis[path[u][v]][v] || (dis[p][v]==dis[path[u][v]][v] && p<path[u][v]))
path[u][v]=p;
}
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=-1;
printf("%.3f\n",dp(cc,kk));
}
感谢mengcier订正