bzoj2702[SDOI2012]走迷宮

來源:互聯網
上載者:User

標籤:from   pac   main   tor   const   else   graph   思路   name   

題意:給你一個有向圖,點數10000,邊數1000000,SCC大小不超過100(按資料範圍的寫法只有第三部分資料滿足這個條件,不過第二部分資料並沒有出現大小大於100個點的SCC,我是用數組大小為100的代碼以身試法的2333)從s出發隨機走,問走到t的期望步數.

首先考慮inf的情況.如果從s出發可以走到一個無法走到t的點,比如這個資料:紅色點為起點,綠色點為終點,那麼有1/2的機率永遠也走不到(在藍色點停下).

注意出現環的情況不一定是INF,因為在環上走無窮步的機率可能是無窮小。於是先縮點,把邊反向找到所有不能到達t的SCC,如果從s出發有可能到達這樣的一個SCC或s本身處於這樣一個SCC,那麼答案是INF。

接下來,我們把期望步數轉化成期望經過的點數(顯然經過的邊數等於點數-1),那麼利用期望的線性性,只需要高斯消元求出每個點的期望經過次數再加起來。但是這個範圍顯然不能直接做。而SCC大小小於100,提醒我們可以對每個SCC分別進行高斯消元,然後考慮SCC之間的關係。思路類似USACO一道最短路題”道路與航線”,那道題是對每個SCC分別跑dijkstra。

具體的做法:記f[i]為點i的期望經過次數,g[i]為從另一個SCC走到點i的期望次數,因為我們按拓撲序處理每個SCC,所以在處理每個SCC的時候這個SCC中每個點的g[]值都已經求出來了.接下來對SCC中每個點列一個方程.對於點x,f[x]=g[x]+sigma(f[j]/outdeg[j]),j向x有一條有向邊且j和x在同一個SCC,outdeg為出度。這裡j可以等於x(有自環),驗證一下,這時候方程也是對的.解完這個SCC之後要用這個SCC裡的點更新其他SCC的g[].注意邊界g[s]=1,f[t]=1

然後碼碼碼就好了。

#include<cstdio>#include<vector>#include<algorithm>using namespace std;int n,m,s,t;const int maxn=10005,maxm=1000005;//Graph Theorystruct edge{  int to,next;}lst1[maxm],lst2[maxm],lst3[maxm];int len1=1,len2=1,len3=1;int first1[maxn],first2[maxn],first3[maxn];void addedge1(int a,int b){  lst1[len1].to=b;lst1[len1].next=first1[a];  first1[a]=len1++;}void addedge2(int a,int b){  lst2[len2].to=b;lst2[len2].next=first2[a];  first2[a]=len2++;}void addedge3(int a,int b){  lst3[len3].to=b;lst3[len3].next=first3[a];  first3[a]=len3++;}int outdeg[maxn];int belong[maxn],tot,sz[maxn];vector<int> scc[maxn];int stk[maxn],top,dfn[maxn],low[maxn],T;bool ins[maxn];namespace Trajan{  void dfs(int x){    low[x]=dfn[x]=++T;    stk[top++]=x;ins[x]=true;    for(int pt=first1[x];pt;pt=lst1[pt].next){      if(!dfn[lst1[pt].to]){    dfs(lst1[pt].to);    if(low[lst1[pt].to]<low[x])low[x]=low[lst1[pt].to];      }else if(ins[lst1[pt].to]&&dfn[lst1[pt].to]<low[x])low[x]=dfn[lst1[pt].to];    }    if(dfn[x]==low[x]){      ++tot;      do{    ins[stk[--top]]=false;    belong[stk[top]]=tot;    scc[tot].push_back(stk[top]);    sz[tot]++;      }while(stk[top]!=x);    }  }  void tarjan(){    for(int i=1;i<=n;++i){      if(!dfn[i])dfs(i);    }    for(int i=1;i<=n;++i){      for(int pt=first1[i];pt;pt=lst1[pt].next){    if(belong[lst1[pt].to]!=belong[i]){      addedge2(belong[lst1[pt].to],belong[i]);      addedge3(belong[i],belong[lst1[pt].to]);    }      }    }  }  bool reachfromend[maxn],mustreachend[maxn];  void predfs(int x){    reachfromend[x]=true;    for(int pt=first2[x];pt;pt=lst2[pt].next){      if(!reachfromend[lst2[pt].to]){    predfs(lst2[pt].to);      }    }  }  bool checkdfs(int x){    if(!reachfromend[x])return false;    for(int pt=first3[x];pt;pt=lst3[pt].next){      if(mustreachend[lst3[pt].to])continue;      if(!checkdfs(lst3[pt].to))return false;    }    return mustreachend[x]=true;  }  bool check(){    predfs(belong[t]);     return checkdfs(belong[s]);  }};double f[maxn],g[maxn];int map[maxn];namespace Work{  bool done[maxn];  double F[105][105];  int rk;  void Swap(int a,int b){    for(int i=0;i<=rk;++i)swap(F[a][i],F[b][i]);  }  void multplus(int a,int b,double times){    for(int i=0;i<=rk;++i)F[a][i]+=F[b][i]*times;  }  void Gauss(int n){    rk=n;    for(int i=1;i<=n;++i){      if(F[i][i]==0){    for(int j=i+1;j<=n;++j){      if(F[j][i]!=0){        Swap(i,j);break;      }    }      }      for(int j=i+1;j<=n;++j)multplus(j,i,-F[j][i]/F[i][i]);    }    for(int i=n;i>=1;--i){      F[i][0]/=F[i][i];      for(int j=i-1;j>=1;--j){    F[j][0]-=F[j][i]*F[i][0];      }    }  }  void build_equations(int x){    for(int i=1;i<=sz[x];++i){      for(int j=0;j<=sz[x];++j){    F[i][j]=0;      }    }    for(int i=0;i<sz[x];++i)F[i+1][0]=-g[scc[x][i]];    for(int i=1;i<=sz[x];++i){      F[i][i]=-1;map[scc[x][i-1]]=i;      if(scc[x][i-1]==t)F[i][0]=-1;    }    for(int i=0;i<sz[x];++i){      if(scc[x][i]==t)continue;      for(int pt=first1[scc[x][i]];pt;pt=lst1[pt].next){    if(belong[lst1[pt].to]==x){      if(lst1[pt].to==t)continue;      F[map[lst1[pt].to]][i+1]+=1.0/outdeg[scc[x][i]];    }      }    }      }  void dfs(int x){    for(int pt=first2[x];pt;pt=lst2[pt].next){      if(!done[lst2[pt].to])dfs(lst2[pt].to);    }    build_equations(x);    Gauss(sz[x]);    for(int i=0;i<sz[x];++i){      f[scc[x][i]]=F[i+1][0];    }    for(int i=0;i<sz[x];++i){      for(int pt=first1[scc[x][i]];pt;pt=lst1[pt].next){    if(belong[lst1[pt].to]!=x){      g[lst1[pt].to]+=f[scc[x][i]]/outdeg[scc[x][i]];    }      }    }    done[x]=true;  }}int main(){  scanf("%d%d%d%d",&n,&m,&s,&t);  int a,b;  for(int i=1;i<=m;++i){    scanf("%d%d",&a,&b);addedge1(a,b);    outdeg[a]++;  }  Trajan::tarjan();  if(Trajan::check()){    g[s]=1;    Work::dfs(belong[t]);    double ans=0;    for(int i=1;i<=n;++i){//printf("%.2f ",f[i]);      ans+=f[i];    }//ans:the expected number of points on the path from s to t    printf("%.3f\n",ans-1);  }else{    printf("INF\n");  }  return 0;}

 

bzoj2702[SDOI2012]走迷宮

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.