bzoj 2707 [SDOI2012]走迷宫(SCC+高斯消元)

你说的曾经没有我的故事 提交于 2020-01-30 04:10:20

 

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来着,但是有圈啊……有圈啊……有圈啊……

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!