zoukankan      html  css  js  c++  java
  • [BZOJ2707]走迷宫

    Description

    Morenan被困在了一个迷宫里。迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T。可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点。这样,Morenan走的步数可能很长,也可能是无限,更可能到不了终点。若到不了终点,则步数视为无穷大。但你必须想方设法求出Morenan所走步数的期望值。

    Input

    第1行4个整数,N,M,S,T
    第[2, M+1]行每行两个整数o1, o2,表示有一条从o1到o2的边。

    Output

    一个浮点数,保留小数点3位,为步数的期望值。若期望值为无穷大,则输出"INF"。
    Sample Input
    9 12 1 9
    1 2
    2 3
    3 1
    3 4
    3 7
    4 5
    5 6
    6 4
    6 7
    7 8
    8 9
    9 7
    Sample Output
    9.500
    HINT
    n<=10000,m<=1000000,保证每个强连通分量大小不超过100
     
    题解
    本题真的是无法描述啊......
    这个高斯消元搞了我一晚上
    正解其实想出来了但是就是不会打
    既然题目都提示强连通分量了,肯定要跑个tarjan缩点呀
    但是,经过一个强连通分量不一定就会INF,因为毕竟一次走不出去还有机会再次走出去
    容易发现,INF的条件是“起点终点不连通”或“起点可以到达某个点,该点却不能到达终点”
    上述INF情况可以跑正向+逆向dfs来判断
    在不INF时,对于每个点,设f[i]为从i点到终点的期望步数,设du[i]为i点出度,f的方程容易想出来:
    f[i]=1+sigma(f[j],i与j有边联通)/du[i]
    (除了终点T,到了终点之后就不用再走了,因此f[T]=0,终点的出边也可以直接删除)
    每个点的f长得和方程一样,那么我们就考虑解方程组:高斯消元
    可我们发现数据范围太大(n<=10000)没办法消元
    我们发现,题目提示强连通分量大小不超过100,100的范围是可以做的
    因此我们考虑按照拓扑序逆序对每一个强连通分量进行高斯消元;
    如果按照拓扑序逆序的话,计算某个连通块时,他会涉及到的出点都已经计算完了,所以这样是正确的
    代码见下
      1 #include<cstdio>
      2 #include<cstring>
      3 #include<queue>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<vector>
      7 using namespace std;
      8 const int N=10100;
      9 const int M=1000100;
     10 struct node{int qi,zhong,next;}s[M],z[M],t[M];
     11 bool vis[N],t_vis[N],z_vis[N];
     12 int e,z_e,t_e,adj[N],z_adj[N],t_adj[N];//s最早的图,z缩点后正图,t缩点后反图 
     13 int n,m,S,T,id[N],chudu[N];//id为某个点在所属连通块 
     14 vector<int>man[N];
     15 int dfn[N],low[N],stack[N],top,num,belong[N],tot;//tarjan相关的数组 
     16 double A[210][210],f[N];//A为高斯消元,f为dp数组 
     17 inline void add(int qi,int zhong)
     18 {
     19     s[++e].zhong=zhong;s[e].qi=qi;
     20     s[e].next=adj[qi];adj[qi]=e;
     21 }
     22 inline void z_add(int qi,int zhong)
     23 {
     24     z[++z_e].zhong=zhong;z[z_e].qi=qi;
     25     z[z_e].next=z_adj[qi];z_adj[qi]=z_e;
     26 }
     27 inline void t_add(int qi,int zhong)
     28 {
     29     t[++t_e].zhong=zhong;t[t_e].qi=qi;
     30     t[t_e].next=t_adj[qi];t_adj[qi]=t_e;
     31 }
     32 void tarjan(int rt)
     33 {
     34     dfn[rt]=low[rt]=++num;
     35     stack[++top]=rt;vis[rt]=1;
     36     for(int i=adj[rt];i;i=s[i].next)
     37     {
     38         int u=s[i].zhong;
     39         if(!dfn[u])tarjan(u),low[rt]=min(low[u],low[rt]);
     40         else if(!id[u])low[rt]=min(dfn[u],low[rt]);
     41     }
     42     if(dfn[rt]==low[rt])
     43     {
     44         int v,ge=0;tot++;
     45         do
     46         {
     47             v=stack[top--];id[v]=++ge;
     48             belong[v]=tot;man[tot].push_back(v);
     49         }
     50         while(v!=rt);
     51     }
     52 }
     53 void dfs1(int rt)
     54 {
     55     z_vis[rt]=1;
     56     for(int i=z_adj[rt];i;i=z[i].next)
     57         if(!z_vis[z[i].zhong])dfs1(z[i].zhong);
     58 }
     59 void dfs2(int rt)
     60 {
     61     t_vis[rt]=1;
     62     for(int i=t_adj[rt];i;i=t[i].next)
     63         if(!t_vis[t[i].zhong])dfs2(t[i].zhong);
     64 }
     65 inline bool judge()//正反dfs判断INF 
     66 {
     67     dfs1(belong[S]);dfs2(belong[T]);
     68     for(int i=1;i<=n;i++)
     69         if(z_vis[i]&&!t_vis[i])
     70             return 0;
     71     return 1;
     72 }
     73 inline void gasse(int b)//高斯消元 
     74 {
     75 
     76     if(b==belong[T]){f[T]=0;return;}
     77     int size=man[b].size();
     78     memset(A,0,sizeof(A));
     79     for(int i=0;i<size;i++)
     80     {
     81         int p=man[b][i];
     82         A[i][size]=chudu[p];//我统一把出度给乘上去了,没有写分数的形式 
     83         for(int j=adj[p];j;j=s[j].next)
     84         {
     85             int u=s[j].zhong;
     86             if(belong[u]==b)//统计连通块自己的系数 
     87                 A[i][id[u]-1]--;
     88             else if(u!=T)//统计之前的贡献 
     89                 A[i][size]+=f[u];
     90         }
     91         A[i][i]+=chudu[p];
     92     }
     93     for(int i=0;i<size;i++)
     94     {
     95         int p=i;
     96         for(int j=i+1;j<size;j++)
     97             if(fabs(A[p][i])<fabs(A[j][i]))p=j;
     98         if(p!=i)
     99             for(int j=0;j<=size;j++)
    100                 swap(A[p][j],A[i][j]);
    101         for(int j=i+1;j<size;j++)
    102         {
    103             double tmp=A[j][i]/A[i][i];
    104                 for(int k=i;k<=size;k++)
    105                     A[j][k]-=tmp*A[i][k];
    106         }    
    107     }
    108     for(int i=size-1;i>=0;i--)
    109     {
    110         for(int j=i+1;j<size;j++)
    111             A[i][size]-=A[j][size]*A[i][j];
    112         A[i][size]/=A[i][i];
    113     }
    114     for(int i=0;i<size;i++)
    115         f[man[b][i]]=A[i][size];
    116 }
    117 void solve(int rt)
    118 {
    119     for(int i=z_adj[rt];i;i=z[i].next)
    120         if(!vis[z[i].zhong])
    121             solve(z[i].zhong);
    122     vis[rt]=1;
    123     gasse(rt);
    124 }
    125 int main()
    126 {
    127     scanf("%d%d%d%d",&n,&m,&S,&T);int a,b;
    128     if(S==T){printf("0.000");return 0;}
    129     for(int i=1;i<=m;i++)
    130     {
    131         scanf("%d%d",&a,&b);
    132         if(a==T)continue;
    133         chudu[a]++,add(a,b);
    134     }
    135     for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    136     for(int i=1;i<=n;i++)
    137     {
    138         for(int j=adj[i];j;j=s[j].next)
    139         {
    140             int u=s[j].zhong;
    141             if(belong[i]!=belong[u])
    142             {
    143                 z_add(belong[i],belong[u]);
    144                 t_add(belong[u],belong[i]);
    145             }
    146         }
    147     }
    148     if(judge())
    149     {
    150         memset(vis,0,sizeof(vis));
    151         solve(belong[S]);
    152         printf("%.3lf",f[S]);
    153     }
    154     else{printf("INF");return 0;}
    155 } 
    BZOJ2707
     
     
     
     
    Progress is not created by contented people.
  • 相关阅读:
    Linux混杂设备驱动学习
    Linux字符设备驱动解析
    U-BOOT-Linux启动指令bootm分析
    项目-基于视频压缩的实时监控系统--tiny6410
    django分页linaro-django-pagination
    django FileFIeld和ImageField 上传路径改写
    ajaxFileUpload用法
    gzip压缩
    编写EL函数
    struts2上传下载
  • 原文地址:https://www.cnblogs.com/LadyLex/p/TSHugh.html
Copyright © 2011-2022 走看看