【JZOJ2758】【SDOI2012】走迷宮(labyrinth)

╰( ̄▽ ̄)╭

Morenan 被困在了一個迷宮裏。
迷宮可以視爲 N 個點 M 條邊的有向圖,其中 Morena n處於起點 S , 迷宮的終點設爲 T 。
可惜的是 , Morenan 非常的腦小 , 他只會從一個點出發隨機沿着一條從該點出發的有向邊 , 到達另一個點 。
這樣 , Morenan 走的步數可能很長 , 也可能是無限,更可能到不了終點。
若到不了終點,則步數視爲無窮大。
但你必須想方設法求出 Morenan 所走步數的期望值。

(⊙ ▽ ⊙)

一開始看着道題,就覺得是tarjan縮點後,轉化成DAG上的問題。

當原圖是DAG時

fi 表示第i 個點走到終點的距離。
容易有fi=jnext(i)1|next(i)|(fj+1)
其中next(i)i 的後繼集合。
很容易使用拓撲排序來完成動態規劃。

當原圖是一般的有向圖時

利用tarjan 算法可以把圖中的強連通分量找出來。
對於任意一個強連通分量,我們利用高斯消元來求解出強連通分量中的每個點的f 值。
套上拓撲排序,就能夠解決。


時間複雜度爲O(nL3) ,其中L 爲最大強連通分量的大小。
實際時間複雜度則遠遠不到。

( ̄~ ̄)

高斯(gauss)消元:

1.目標

nn 元一次方程求解。

2.步驟

首先:
把某條方程的第一個元的係數化爲一,利用它可以消去其他方程的第一元。
以此類推,可以消去第二個元、第三個元……
最後,會只剩下一條只關於最後一元的方程,實際上就是這一元的根。
然後:
得出最後一元的根後,就可以代入先前的方程。
於是可以算出所有元的根。

(⊙v⊙)

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
#define ll long long
using namespace std;
const char* fin="jzoj2758.in";
const char* fout="jzoj2758.out";
const int Inf=0x7fffffff;
const int maxn=20007,maxm=2000007,maxk=107;
int n,m,St,En,i,j,k,N,ti;
int fi[maxn],ne[maxm],la[maxm],tot;
int Fi[maxn],Ne[maxm],La[maxm],Tot;
int dfn[maxn],low[maxn],num,st[maxn],be[maxn];
bool bz[maxn],End;
int inf[maxn];
int az[maxn];
int ha[maxn][maxk],ru[maxn],id[maxn],tow[maxn];
double f[maxn],gs[maxk][maxk];
int b[maxn],head,tail;
void add_line(int a,int b){
    tot++;
    ne[tot]=fi[a];
    la[tot]=b;
    fi[a]=tot;
}
void Add_line(int a,int b){
    Tot++;
    Ne[Tot]=Fi[a];
    La[Tot]=b;
    Fi[a]=Tot;
}
void tarjan(int v){
    int i,j,k;
    dfn[v]=low[v]=++num;
    bz[st[j=++st[0]]=v]=true;
    for (k=fi[v];k;k=ne[k])
        if (!dfn[la[k]]){
            tarjan(la[k]);
            low[v]=min(low[v],low[la[k]]);
        }else if (bz[la[k]]) low[v]=min(low[la[k]],low[v]);
    if (low[v]==dfn[v]){
        N++;
        be[N]=0;
        while (st[0]>=j){
            ha[N][++ha[N][0]]=st[st[0]];
            be[st[st[0]]]=N;
            bz[st[st[0]--]]=false;
        }
    }
}
double ABS(double x){
    return x>0?x:-x;
}
void add(int v){
    b[++tail]=v;
}
void count(int v,int n){
    int i,j,k,l;
    double tmp,tmd;
    ti++;
    for (i=1;i<=n-1;i++){
        for (j=1;j<n;j++){
            if (az[j]<ti && (gs[j][i]>10e-13 || gs[j][i]<-10e-13)){
                az[j]=ti;
                tow[i]=j;
                tmp=1.0/gs[j][i];
                for (k=1;k<=n;k++) gs[j][k]*=tmp;
                for (k=1;k<n;k++){
                    if (k==j) continue;
                    tmd=gs[k][i];
                    for (l=1;l<=n;l++)
                        gs[k][l]-=tmd*gs[j][l];
                }
                break;
            }
        }
    }
    for (i=n-1;i>=1;i--){
        f[ha[v][tow[i]]]=-gs[tow[i]][n];
        for (j=1;j<=n-1;j++){
            gs[j][n]-=gs[j][i]*gs[tow[i]][n];
        }
    }
}
void work(int v){
    int i,j,k;
    for (i=1;i<=ha[v][0];i++) id[ha[v][i]]=i;
    for (i=1;i<=ha[v][0];i++){
        for (j=1;j<=ha[v][0]+1;j++) gs[i][j]=0;
        j=0;
        for (k=Fi[ha[v][i]];k;k=Ne[k]){
            gs[i][ha[v][0]+1]+=1;
            gs[i][i]-=1;
            if (f[La[k]]>10e-7 || La[k]==En) gs[i][ha[v][0]+1]+=f[La[k]];
            else gs[i][id[La[k]]]+=1;
        }
    }
    count(v,ha[v][0]+1);
}
void update(int v){
    int i,j,k;
    for (i=1;i<=ha[v][0];i++)
        for (k=fi[ha[v][i]];k;k=ne[k]){
            inf[be[la[k]]]=max(inf[be[la[k]]],inf[v]);
            if (!--ru[be[la[k]]]) add(be[la[k]]);
        }
}
void topsort(){
    int i,j,k;
    head=tail=0;
    memset(f,0,sizeof(f));
    f[En]=0;
    for (i=n+1;i<=N;i++)
        if (!ru[i]){
            add(i);
        }
    while (head++<tail){
        if (be[En]==b[head]) inf[b[head]]=1;
        if (inf[b[head]]==0) inf[b[head]]=2;
        if (inf[b[head]]==1 && b[head]!=be[En]) work(b[head]);
        update(b[head]);
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&St,&En);
    N=n;
    for (i=1;i<=m;i++){
        scanf("%d%d",&j,&k);
        if (j!=En){
            Add_line(j,k);
            add_line(k,j);
        }
    }
    for (i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
    for (i=1;i<=n;i++)
        for (k=fi[i];k;k=ne[k])
            if (be[la[k]]!=be[i]) ru[be[la[k]]]++;
    topsort();
    //printf("%3.lf",f[St]);
    if (inf[be[St]]!=1) printf("INF");
    else printf("%.3lf",f[St]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章