zoukankan      html  css  js  c++  java
  • bzoj 2707: [SDOI2012]走迷宫

    http://www.lydsy.com/JudgeOnline/problem.php?id=2707

    dp[i] 表示从点i到终点的期望步数

    dp[i]= Σ (dp[j]+1)/out[i]

    j表示i的出边指向的店,out[i] 表示i的出边数

    如果图是一张DAG,那么直接在反图 上 拓扑排序DP即可

    现在有环,那就缩点,环上的用高斯消元

    无解的情况:

    1、起点走不到终点

    2、存在一个联通块,起点能走到他,但这个联通块没有出边,且不是终点所在的联通块

    因为此时一旦步入这个联通块将永远走不出去

    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    
    #define N 10001
    #define M 1000001
    
    using namespace std;
    
    int front[N],to[M],nxt[M],tot;
    int front_[N],to_[M],nxt_[M],tot_;
    
    int dfn[N],low[N],id;
    int st[N],top;
    bool vis[N];
    
    vector<int>block[N];
    int bl[N],cnt;
    int num[N];
    
    double out[N];
    int in_[N];
    
    bool vis_block[N];
    
    double a[101][101],dp[N];
    
    queue<int>q;
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to_[++tot_]=u; nxt_[tot_]=front_[v]; front_[v]=tot_;
    }
    
    void tarjan(int x)
    {
        dfn[x]=low[x]=++id;
        st[++top]=x;
        vis[x]=true;
        for(int i=front[x];i;i=nxt[i])
            if(!dfn[to[i]])
            {
                tarjan(to[i]);
                low[x]=min(low[x],low[to[i]]);
            }
            else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
        if(dfn[x]==low[x])
        {
            cnt++;
            while(st[top]!=x)
            {
                block[cnt].push_back(st[top]);
                bl[st[top]]=cnt;
                num[st[top]]=block[cnt].size()-1;
                vis[st[top--]]=false;
            }
            block[cnt].push_back(x);
            bl[x]=cnt;
            num[x]=block[cnt].size()-1;
            vis[st[top--]]=false;
        }
    }
    
    void dfs(int x)
    {
        vis[x]=vis_block[bl[x]]=true;
        for(int i=front[x];i;i=nxt[i])
            if(!vis[to[i]]) dfs(to[i]);
    }
    
    void gauss(int n)
    {
        int r; double t;
        for(int i=0;i<n;++i)
        {
            r=i;
            for(int j=i+1;j<n;++j)
                if(fabs(a[j][i])>fabs(a[r][i])) r=j;
            if(r!=i)
                for(int j=0;j<=n;++j) swap(a[r][j],a[i][j]);
            for(int k=i+1;k<n;++k)
            {
                t=a[k][i]/a[i][i];
                for(int j=i;j<=n;++j) a[k][j]-=t*a[i][j];
            }
        }
        for(int i=n-1;i>=0;--i)
        {
            for(int j=i+1;j<n;++j) a[i][n]-=a[i][j]*a[j][n];
            a[i][n]/=a[i][i];
        }
    }
    
    int main()
    {
        int n,m,s,t;
        read(n); read(m); read(s); read(t);
        int u,v;
        for(int i=1;i<=m;++i)
        {
            read(u); read(v);
            add(u,v); out[u]++;
        }
        for(int i=1;i<=n;++i)
            if(!dfn[i]) tarjan(i);
        dfs(s);
        if(!vis[t])
        {
            printf("INF");
            return 0;
        }
        for(int i=1;i<=n;++i)
            for(int j=front[i];j;j=nxt[j])
                if(bl[i]!=bl[to[j]]) in_[bl[i]]++;
        for(int i=1;i<=cnt;++i)
            if(vis_block[i] && !in_[i] && i!=bl[t])
            {
                printf("INF");
                return 0;
            }
        for(int i=1;i<=n;++i) out[i]=1.0/out[i];
        q.push(bl[t]);
        int now,siz,x;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            memset(a,0,sizeof(a));
            siz=block[now].size();
            for(int i=0;i<siz;++i)
            {
                x=block[now][i];
                a[i][i]=1;
                a[i][siz]=dp[x];
                if(x==t) continue;
                for(int j=front[x];j;j=nxt[j])
                    if(bl[to[j]]==now)
                    {
                        a[i][siz]+=out[x];
                        a[i][num[to[j]]]-=out[x];
                    }
            }
            gauss(siz);
            for(int i=0;i<siz;++i)
            {
                x=block[now][i];
                dp[x]=a[i][siz];
                for(int j=front_[x];j;j=nxt_[j])
                    if(bl[to_[j]]!=now)
                    {
                        --in_[bl[to_[j]]];
                        if(!in_[bl[to_[j]]]) q.push(bl[to_[j]]);
                        dp[to_[j]]+=(dp[x]+1)*out[to_[j]];
                    }
            }
        }
        printf("%.3lf",dp[s]);
    }
  • 相关阅读:
    使用Dubbox构架分布式服务
    Elasticsearch搜索之explain评分分析
    Elasticsearch搜索之most_fields分析
    Elasticsearch搜索之cross_fields分析
    Elasticsearch搜索之best_fields分析
    Elasticsearch高级搜索排序( 中文+拼音+首字母+简繁转换+特殊符号过滤)
    ibatis2.3中#和$符号的区别(转)
    读文章有感
    图片bmp格式转换为jpg格式
    IndexOf、LastIndexOf、Substring的用法
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8603975.html
Copyright © 2011-2022 走看看