zoukankan      html  css  js  c++  java
  • BZOJ_1415_[Noi2005]聪聪和可可_概率DP+bfs

    BZOJ_1415_[Noi2005]聪聪和可可_概率DP+bfs

    Description

    Input

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

    Output

    输出1个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会把可可吃掉。

    Sample Input

    【输入样例1】
    4 3
    1 4
    1 2
    2 3
    3 4
    【输入样例2】
    9 9
    9 3
    1 2
    2 3
    3 4
    4 5
    3 6
    4 6
    4 7
    7 8
    8 9

    Sample Output

    【输出样例1】
    1.500
    【输出样例2】
    2.167


    先求出dis[i][j]表示i和j之间的最短路,这步只需要对n个点进行bfs。

    然后推出mov[i][j]表示聪聪在i点,可可在j点时聪聪再走一步会去几号点。

    设F[i][j]表示聪聪在i点,可可在j点,聪聪吃到可可的期望步数。

    因为聪聪一次走两步,可可每次走一步。

    相当于每个回合聪聪都离可可进了一步。

    于是DP转移是没有环的,直接记忆化搜索即可。

    代码:

    #include <cstdio>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 1050
    #define inf 0x3f3f3f3f
    typedef double f2;
    f2 f[N][N];
    int head[N],to[N<<1],nxt[N<<1],cnt,dis[N][N],n,m,S,T,Q[N],l,r,mov[N][N],out[N],vis[N];
    inline void add(int u,int v) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; out[u]++;
    }
    void bfs(int s) {
        memset(vis,0,sizeof(vis)); l=r=0;
        memset(dis[s],0x3f,sizeof(dis[s]));
        Q[r++]=s;
        while(l<r) {
            int x=Q[l++],i; vis[x]=1;
            for(i=head[x];i;i=nxt[i]) {
                if(!vis[to[i]]) {
                    dis[s][to[i]]=dis[s][x]+1; vis[to[i]]=1;
                    Q[r++]=to[i];
                }
            }
        }
    }
    f2 DP(int s,int t) {
        if(f[s][t]!=-1) return f[s][t];
        if(s==t) return f[s][t]=0;
        f2 re=0;
        int i,t1=mov[s][t],t2=mov[t1][t];
        if(t1==t||t2==t) return 1;
        for(i=head[t];i;i=nxt[i]) {
            int y=to[i];
            re+=DP(t2,y)+1;
        }
        re+=DP(t2,t)+1;
        return f[s][t]=re/(out[t]+1);
    }
    int main() {
        scanf("%d%d",&n,&m);
        int i,x,y,j,k;
        scanf("%d%d",&S,&T);
        for(i=1;i<=m;i++) {
            scanf("%d%d",&x,&y); add(x,y); add(y,x);
        }
        for(i=1;i<=n;i++) bfs(i);
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                f[i][j]=-1;
                if(i!=j) {
                    for(k=head[i];k;k=nxt[k]) {
                        if(!mov[i][j]) mov[i][j]=to[k];
                        else if(dis[to[k]][j]<dis[mov[i][j]][j]||(dis[to[k]][j]==dis[mov[i][j]][j]&&to[k]<mov[i][j])) mov[i][j]=to[k];
                    }
                }
            }
        }
        printf("%.3f
    ",DP(S,T));
    }
    
  • 相关阅读:
    TCP中的三次握手与四次挥手
    C++中的访问控制与封装
    C++中的类定义
    Verilog学习笔记设计和验证篇(三)...............同步有限状态机的指导原则
    Verilog学习笔记简单功能实现(三)...............同步有限状态机
    Verilog学习笔记设计和验证篇(二)...............同步有限状态机
    Verilog学习笔记设计和验证篇(一)...............总线和流水线
    Verilog学习笔记简单功能实现(二)...............全加器
    Verilog HDL模型的不同抽象级别
    Verilog学习笔记简单功能实现(一)...............D触发器
  • 原文地址:https://www.cnblogs.com/suika/p/9186154.html
Copyright © 2011-2022 走看看