[BZOJ2707]走迷宫
生活随笔
收集整理的這篇文章主要介紹了
[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?
?
轉載于:https://www.cnblogs.com/LadyLex/p/TSHugh.html
總結
以上是生活随笔為你收集整理的[BZOJ2707]走迷宫的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS6.6上进程挂起的诡异问题和
- 下一篇: 【BZOJ3994】[SDOI2015]