zoukankan      html  css  js  c++  java
  • [2019.3.7]BZOJ1415 [Noi2005]聪聪和可可

    首先,我们记录(mo_{i,j})表示在点(i)到点(j)的任意一条最短路上,并且和(i)相邻的标号最小的节点,也就是当聪聪在点(i),可可在点(j)时,聪聪下一步会走的节点。

    显然可以对每一个点(i)跑最短路计算(mo_i)

    使用堆优化的Dijkstra的话这部分的总时间复杂度是(O(n^2log n))

    然后进行dfs,记(dfs(x,y))表示聪聪在(x),可可在(y)时的期望步数。

    那么:

    (x=y),直接返回0;

    (mo_{x,y}=y)(mo_{mo_{x,y},y}=y),即聪聪走两步以下就可以抓到可可,返回1;

    否则,设(mo_{mo_{x,y},y}=to),与(y)相邻的节点数量为(m),分别是(p_1,p_2,p_3,...,p_m)

    那么答案=(frac{sum_{t=1}^m[dfs(to,p_i)+1]+dfs(to,y)}{m+1})

    显然不会死循环,因为每一次递归聪聪和可可的距离至少减少1。

    可是这样会TLE。

    所以我们要记忆化搜索。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int INF=1e9;
    struct edge{
        int t,nxt;
    }e[2010];
    struct node{
        int id,v;
        bool operator>(const node&y)const{
            return v==y.v?id<y.id:v<y.v;
        }
        bool operator<(const node&y)const{
            return v==y.v?id>y.id:v>y.v;
        }
    }t;
    int n,m,u,v,a,b,p[1010],cnt,be[1010],mo[1010][1010],vis[1010],mn[1010];
    double s[1010][1010];
    priority_queue<node>q;
    void add(int x,int y){
        e[++cnt].t=y,e[cnt].nxt=be[x],be[x]=cnt;
    }
    void Dijkstra(int x){
        for(int i=1;i<=n;++i)mn[i]=INF,vis[i]=0;
        mn[x]=0,mo[x][x]=0,q.push((node){x,0});
        while(!q.empty()){
            while(!q.empty()&&(t=q.top(),vis[t.id]))q.pop();
            if(q.empty())return;
            q.pop(),vis[t.id]=1;
            for(int i=be[t.id];i;i=e[i].nxt)mo[x][e[i].t]>mo[x][t.id]&&mn[e[i].t]==mn[t.id]+1?mo[x][e[i].t]=(t.id==x?e[i].t:mo[x][t.id]):0,mn[e[i].t]>t.v+1?mn[e[i].t]=t.v+1,mo[x][e[i].t]=(t.id==x?e[i].t:mo[x][t.id]),q.push((node){e[i].t,mn[e[i].t]}),0:0;
        }
    }
    double dfs(int x,int y){
        if(x==y)return 0;
        if(s[x][y])return s[x][y];
        if(mo[x][y]==y)return s[x][y]=1;
        int to=mo[mo[x][y]][y];
        if(to==y)return s[x][y]=1;
        double ans=0;
        for(int i=be[y];i;i=e[i].nxt)ans+=dfs(to,e[i].t)+1;
        ans+=dfs(to,y)+1;
        return s[x][y]=1.0*ans/p[y];
    }
    int main(){
        scanf("%d%d%d%d",&n,&m,&a,&b);
        for(int i=1;i<=m;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u),++p[u],++p[v];
        for(int i=1;i<=n;++i)++p[i],Dijkstra(i);
        printf("%.3lf",dfs(a,b));
        return 0;
    }
    
  • 相关阅读:
    使用PyDNS查询
    C#结构体
    使用CreateProcess函数运行其他程序
    运算符重载
    C#学习抽象类和方法
    sed命令使用
    Python For Delphi 示例
    建立Socket
    使用 lambda 函数
    C#接口实现
  • 原文地址:https://www.cnblogs.com/xryjr233/p/BZOJ1415.html
Copyright © 2011-2022 走看看