bzoj1415: [Noi2005]聪聪和可可

spfa+dp。

首先用一个类似spfa的过程求出a[s][t],聪聪在s,可可在t时,聪聪第一步怎么走。

然后dp求出f[s][t],表示聪聪在s,可可在t的期望步数。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1000 + 10;
const int maxm = 2000 + 10;

int g[maxn],v[maxm],next[maxm],eid;
int n,m,s,t,u;
int q[maxm*10],l,r;
int deg[maxn],dist[maxn],a[maxn][maxn];
double f[maxn][maxn];
bool inque[maxn];

void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; next[eid]=g[b]; g[b]=eid++;
    deg[a]++; deg[b]++;
}

void spfa(int s) {
    memset(dist,0x3f,sizeof(dist)); l=r=0;
    dist[s]=0; a[s][s]=s;
    for(int i=g[s];~i;i=next[i]) {
        dist[v[i]]=1;
        a[s][v[i]]=v[i];
        inque[q[r++]=v[i]]=1;        
    }
    
    while(l<r) {
        inque[u=q[l++]]=0;
        for(int i=g[u];~i;i=next[i]) 
            if(dist[v[i]]>dist[u]+1) {
                dist[v[i]]=dist[u]+1;
                a[s][v[i]]=a[s][u];
                if(!inque[v[i]]) 
                    inque[q[r++]=v[i]]=1;
            }
            else if(dist[v[i]]==dist[u]+1 && a[s][u]<a[s][v[i]] ) {
                a[s][v[i]]=a[s][u];
                if(!inque[v[i]]) 
                    inque[q[r++]=v[i]]=1;
            }
        }
    //for(int i=1;i<=n;i++) printf("a[%d][%d]=%d
",s,i,a[s][i]);    
        
}


double dp(int s,int t) {
    if(f[s][t]>=0) return f[s][t];
    int p=a[a[s][t]][t];
    double sum=0;
    if(p==t) return f[s][t]=1;
    for(int i=g[t];~i;i=next[i]) sum+=dp(p,v[i]);
    sum+=dp(p,t);
    return f[s][t]=sum/(deg[t]+1)+1;
}

int main() {
    memset(g,-1,sizeof(g));
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1,a,b;i<=m;i++) {
        scanf("%d%d",&a,&b);
        addedge(a,b);
    }
    for(int i=1;i<=n;i++) spfa(i);
    
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) f[i][j]=-1;
        f[i][i]=0;    
    }
    printf("%.3lf
",dp(s,t));
    return 0;
}
原文地址:https://www.cnblogs.com/invoid/p/5632808.html