【NOI2005】bzoj1415 聪聪和可可

175 篇文章 0 订阅
18 篇文章 0 订阅

Description Input 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数。
第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号。
接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路。
所有的路都是无向的,即:如果能从A走到B,就可以从B走到A。
输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连。 Output
输出1个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会把可可吃掉。

dp[i][j] 表示猫在点 i ,老鼠在点j,猫吃掉老鼠的期望步数。猫走的下一步可以预处理出来,因此只需要枚举老鼠下一步走到哪里。因为猫走两步,老鼠走一步,二者的距离一定是越来越近的,也就是dp转移是一个拓扑图。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int oo=0x3f3f3f3f;
int fir[1010],ne[2010],to[2010],f[1010][1010],que[2010],from[2010],dis[2010],
n,m;
double dp[1010][1010];
void add(int num,int u,int v)
{
    ne[num]=fir[u];
    fir[u]=num;
    to[num]=v;
}
double dfs(int u,int v)
{
    if (dp[u][v]>=0) return dp[u][v];
    if (u==v) return dp[u][v]=0;
    if (f[u][v]==v||f[f[u][v]][v]==v) return dp[u][v]=1;
    int x=f[f[u][v]][v],cnt=1;
    for (int i=fir[v];i;i=ne[i]) cnt++;
    dp[u][v]=1+dfs(x,v)/cnt;
    for (int i=fir[v];i;i=ne[i]) dp[u][v]+=dfs(x,to[i])/cnt;
    return dp[u][v];
}
int main()
{
    int hd,tl,u,v,s,t;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(i<<1,u,v);
        add(i<<1|1,v,u);
    }
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=n;j++) dis[j]=oo;
        dis[i]=0;
        hd=1,tl=0;
        for (int j=fir[i];j;j=ne[j])
        {
            dis[v=to[j]]=1;
            que[++tl]=v;
            from[v]=v;
        }
        while (hd<=tl)
        {
            u=que[hd++];
            f[i][u]=from[u];
            for (int j=fir[u];j;j=ne[j])
                if (dis[u]+1<dis[v=to[j]]||(dis[u]+1==dis[v]&&from[u]<from[v]))
                {
                    if (dis[v]==oo) que[++tl]=v;
                    dis[v]=dis[u]+1;
                    from[v]=from[u];
                }
        }
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            dp[i][j]=-1;
    printf("%.3f\n",dfs(s,t));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值