zoukankan      html  css  js  c++  java
  • bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)

     

    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"。
    【样例输入1】
    6 6 1 6
    1 2
    1 3
    2 4
    3 5
    4 6
    5 6
    【样例输出1】
    3.000
    【样例输入2】
    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
    【样例输出2】
    9.500
    【样例输入3】
    2 0 1 2
    【样例输出3】
    INF
    【数据范围】
    测试点
    N
    M
    Hint
    [1, 6]
    <=10
    <=100
     
    [7, 12]
    <=200
    <=10000
     
    [13, 20]
    <=10000
    <=1000000
    保证强连通分量的大小不超过100
     
     
    另外,均匀分布着40%的数据,图中没有环,也没有自环

    【思路】

           节点u的期望为E(u)=ΣE(v)/deg(u)+1,移项变成deg(u)*E(u)-ΣE(v)=deg(u),而且题目中说到每一个scc中的点数不超过100。我们就可以先划一下scc,将多个节点方程联立,在每个scc中用高斯消元求每个结点的E,O(n^2)。然后再缩点后的图上dfs统计一下就可以啦。

           需要注意应该把t的所有出边切掉,因为我们规定E(t)=0。还有就是如果一个scc中有连往scc外的边,我们把常数项加个E

           因为我们切了几条边,所以判断得改一下,不能直接判断sccno[S]是否直接到达sccno[T],可以两个点都dfs一遍,如果有sccno[S]不可以到达但sccno[T]可以到达的则为INF,此时出现有一个scc不能到达sccno[T]的情况,于是可以在这个scc中转来转去,即inf。

    【代码】

      1 #include<stack>
      2 #include<cmath>
      3 #include<vector>
      4 #include<cstdio>
      5 #include<cstring>
      6 #include<iostream>
      7 #include<algorithm>
      8 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
      9 using namespace std;
     10 
     11 const int N = 1e4+5;
     12 
     13 vector<int> g[3][N];
     14 int n,m,S,T,vis[N],deg[N];
     15 double ans[N],mat[101][101];
     16 
     17 int pre[N],sccno[N],id[N],lowlink[N],dfsc,scccnt;
     18 stack<int> st; vector<int> scc[N];
     19 
     20 void tarjan(int flag,int u) {
     21     pre[u]=lowlink[u]=++dfsc;
     22     st.push(u); deg[u]=(int)g[flag][u].size();
     23     for(int i=0;i<deg[u];i++) {
     24         int v=g[flag][u][i];
     25         if(!pre[v]) {
     26             tarjan(flag,v);
     27             lowlink[u]=min(lowlink[u],lowlink[v]);
     28         }
     29         else if(!sccno[v])
     30             lowlink[u]=min(lowlink[u],pre[v]);
     31     }
     32     if(pre[u]==lowlink[u]) {
     33         ++scccnt;
     34         for(;;) {
     35             int x=st.top(); st.pop();
     36             sccno[x]=scccnt;
     37             scc[scccnt].push_back(x);
     38             id[x]=(int)scc[scccnt].size()-1;
     39             if(x==u) break;
     40         }
     41     }
     42 }
     43 
     44 void gause(int x) {
     45      int n=(int)scc[x].size(),i,j,k,r;
     46     for(i=0;i<n;i++) {
     47         int u=scc[x][i];
     48         for(j=0;j<n;j++) mat[i][j]=0;
     49         mat[i][n]=deg[u];
     50         for(j=0;j<g[0][u].size();j++) {
     51             int v=g[0][u][j];
     52             if(sccno[v]==x) {
     53                 mat[i][id[v]]--;
     54             } else {
     55                 mat[i][n]+=ans[v];
     56             }
     57         }
     58         mat[i][i]+=deg[u];
     59     }
     60     for(i=0;i<n;i++) {
     61         r=i;
     62         for(j=i+1;j<n;j++)
     63             if(fabs(mat[j][i])>fabs(mat[r][i])) r=j;
     64         if(r!=i) for(j=0;j<=n;j++) swap(mat[i][j],mat[r][j]);
     65         for(k=i+1;k<n;k++) {
     66             double f=mat[k][i]/mat[i][i];
     67             for(j=i;j<=n;j++) mat[k][j]-=f*mat[i][j];
     68         }
     69     }
     70     for(i=n-1;i>=0;i--) {
     71         for(j=i+1;j<n;j++)
     72             mat[i][n]-=mat[j][n]*mat[i][j];
     73         mat[i][n]/=mat[i][i];
     74     }
     75     for(i=0;i<n;i++)
     76         ans[scc[x][i]]=mat[i][n];
     77 }
     78 
     79 void solve(int u) {
     80     if(u==sccno[T]) {
     81         ans[T]=0; return ;
     82     }
     83     for(int i=0;i<g[1][u].size();i++) {
     84         int v=g[1][u][i];
     85         if(!vis[v]) solve(v);
     86     }
     87     vis[u]=1;
     88     gause(u);
     89 }
     90 
     91 int mark[3][N];
     92 void dfs(int flag,int u) {
     93     mark[flag][u]=1;
     94     for(int i=0;i<g[flag][u].size();i++) {
     95         int v=g[flag][u][i];
     96         if(!mark[flag][v]) dfs(flag,v);
     97     }
     98 }
     99 int main() {
    100     scanf("%d%d%d%d",&n,&m,&S,&T);
    101     S--,T--;
    102     int u,v;
    103     for(int i=0;i<m;i++) {
    104         scanf("%d%d",&u,&v);
    105         u-- , v--;
    106         if(u==T) continue;
    107         g[0][u].push_back(v);
    108     }
    109     for(int i=0;i<n;i++)
    110         if(!pre[i]) tarjan(0,i);
    111     for(int i=0;i<n;i++) {
    112         for(int j=0;j<g[0][i].size();j++) {
    113             int v=g[0][i][j];
    114             if(sccno[i]!=sccno[v]) {
    115                 g[1][sccno[i]].push_back(sccno[v]);
    116                 g[2][sccno[v]].push_back(sccno[i]);
    117             }
    118         }
    119     }
    120     dfs(1,sccno[S]); dfs(2,sccno[T]);
    121     for(int i=1;i<=scccnt;i++)
    122         if(mark[1][i]&&!mark[2][i]) {
    123             puts("INF"); return 0;
    124         }
    125     solve(sccno[S]);
    126     printf("%.3f",ans[S]);
    127     return 0;
    128 }

    PS: 

    这个题=-= 好神啊0_0

    其实第一眼蒟蒻是想dfs来着,但是有圈啊……有圈啊……有圈啊……

  • 相关阅读:
    自增主键强制修改
    网页速度优化
    JS 获取字符串长度, 区别中英文
    SQL时间相关 SQL日期,时间比较
    关于document.cookie的使用
    php文件头部空白影响CSS布局 2
    FlvPlayer 播放器代码
    JAVA——继承、多态、重载和重写转
    JS星级评分,带提示(转)
    web 启动 本地应用程序 Activity
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5228819.html
Copyright © 2011-2022 走看看