[NOI2005]聪聪与可可

题目大意:有小a和小b,其中一个人到处乱走,每次走一步;另一个人抄近路逼近,每次1-2步。求期望路程。

整解:跑1000遍最短路/bfs,求两两距离,然后找从x逼近y第一步去哪,最后期望dp收场。

dp方程很简单,关键在于实现。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1050
int n,E,xr,xz,hed[N],cnt;
double ind[N];
struct EG
{
    int to,nxt;
}e[2*N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
int dis[N][N],chos[N][N];
bool vis[N];
struct node
{
    int x,d;
    node(){}
    node(int x,int d):x(x),d(d){}
    friend bool operator < (node a,node b)
    {
        return a.d>b.d;
    }
}tp;
priority_queue<node>q;
void dij(int rt)
{
    dis[rt][rt]=0;
    memset(vis,0,sizeof(vis));
    q.push(node(rt,0));
    while(!q.empty())
    {
        tp = q.top();
        q.pop();
        int u = tp.x;
        if(vis[u])continue;
        vis[u]=1;
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(dis[rt][to]>dis[rt][u]+1)
            {
                dis[rt][to]=dis[rt][u]+1;
                q.push(node(to,dis[rt][to]));
            }
        }
    }
}
double f[N][N];
double dp(int x,int y)
{
    if(f[x][y]+1.0!=0)return f[x][y];
    if(x==y)return f[x][y]=0.0;
    if(dis[x][y]<=2)return f[x][y]=1.0;
    f[x][y]=0;
    int k = chos[chos[x][y]][y];//走两步 
    for(int j=hed[y];j;j=e[j].nxt)
        f[x][y]+=dp(k,e[j].to);
    f[x][y]+=dp(k,y);
    f[x][y] = (f[x][y]/(ind[y]+1.0))+1.0;
    return f[x][y];
}
int main()
{
//    freopen("eat.in","r",stdin);
//    freopen("eat.out","w",stdout);
    scanf("%d%d%d%d",&n,&E,&xr,&xz);
    for(int u,v,i=1;i<=E;i++)
    {
        scanf("%d%d",&u,&v);
        ae(u,v),ae(v,u);
        ind[u]++,ind[v]++;
    }
    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=n;i++)
        dij(i);
    memset(chos,0x3f,sizeof(chos));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(dis[i][j]==0x3f3f3f3f||i==j)continue;
            for(int k=hed[i];k;k=e[k].nxt)
            {
                int to = e[k].to;
                if(dis[to][j]+1==dis[i][j]&&to<chos[i][j])
                    chos[i][j]=to;
            }
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=-1.0;
    printf("%.3lf
",dp(xr,xz));
    return 0;
}
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9743697.html