2707: [SDOI2012]走迷宫 tarjan+高斯消元解期望方程组

来源:互联网 发布:淘宝商品排名软件 编辑:程序博客网 时间:2024/04/28 04:48

SDOI2012啊,不错的一道题。
点数很多,我们不能直接高斯消元,而题目中提示了每个强连通分量的点数<=100,我们就可以先tarjan缩一下环。
先说一下无解的情况,如果有一个强连通分量到不了T,就可以在这个强连通分量内无限的走,答案为INF,dfs一下就可以解决。
考虑有解的情况,这就成了DAG上的期望DP问题,我们可以用fi表示从i走到T的期望步数,初始fT=0,那么fi可以在dfs的过程中由点i的后继转移而来,但是每个强连通分量内的点我们要用高斯消元来求,由于不超过100所以高斯消元完全可以解决。

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#define N 10005#define M 1000005using namespace std;vector<int> V[N];double f[N],a[105][105];int n,m,S,T,tot,top,cnt,scc;int dfn[N],low[N],belong[N],du[N],rank[N],vis[N],stack[N],head[N];int list[M],next[M];bool inset[N];inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}inline void insert(int x,int y){    next[++cnt]=head[x];    head[x]=cnt;    list[cnt]=y;    du[x]++;}void tarjan(int x){    dfn[x]=low[x]=++tot;    stack[++top]=x;    inset[x]=true;    for (int i=head[x];i;i=next[i])        if (!dfn[list[i]])        {            tarjan(list[i]);            low[x]=min(low[x],low[list[i]]);        }        else if (inset[list[i]]) low[x]=min(low[x],dfn[list[i]]);    if (dfn[x]==low[x])    {        int i=-1;        scc++;        while (i!=x)        {            i=stack[top--];            belong[i]=scc;            rank[i]=V[scc].size();            V[scc].push_back(i);            inset[i]=false;        }    }}void dfs(int x){    vis[x]=2;    if (x==belong[T])     {        vis[x]=1;        return;    }    for (int i=0;i<V[x].size();i++)        for (int j=head[V[x][i]];j;j=next[j])            if (belong[list[j]]!=x)            {                if (!vis[belong[list[j]]])                     dfs(belong[list[j]]);                if (vis[belong[list[j]]]==1)                     vis[x]=1;            }}void get_ans(int x){    int n=V[x].size();    for (int i=0;i<n;i++)        for (int j=head[V[x][i]];j;j=next[j])            if (belong[list[j]]!=x&&!vis[belong[list[j]]])                 get_ans(belong[list[j]]);    memset(a,0,sizeof(a));    for (int i=0;i<n;i++)    {        a[i][i]=1;        if (V[x][i]==T) continue;        a[i][V[x].size()]=1;        for (int j=head[V[x][i]];j;j=next[j])            if (belong[list[j]]==x)                 a[i][rank[list[j]]]-=1.0/du[V[x][i]];            else a[i][V[x].size()]+=1.0/du[V[x][i]]*f[list[j]];    }    for (int i=0;i<n;i++)    {        double t=a[i][i];        for (int j=0;j<=n;j++)             a[i][j]/=t;        for (int j=0;j<n;j++)            if (j!=i)             {                double t=a[j][i];                for (int k=0;k<=n;k++)                     a[j][k]-=t*a[i][k];            }    }    for (int i=0;i<n;i++)        f[V[x][i]]=a[i][n];    vis[x]=1;}int main(){    n=read(); m=read(); S=read(); T=read();    for (int i=1;i<=m;i++)    {        int u=read(),v=read();        insert(u,v);     }    for (int i=1;i<=n;i++)        if (!dfn[i]) tarjan(i);    memset(vis,0,sizeof(vis));    dfs(belong[S]);    for (int i=1;i<=scc;i++)        if (vis[i]==2)         {            puts("INF");            return 0;        }    memset(vis,0,sizeof(vis));    get_ans(belong[S]);    printf("%.3lf\n",f[S]);    return 0;}
0 0
原创粉丝点击