[HDU4035]Maze

壹、题目描述 ¶

传送门 to HDU.

贰、题解 ¶

设计状态 \(F(u)\) 表示从 \(u\) 开始,走出去时期望经过的边数,那么我们不难设计出一份代码:

\[\begin{aligned} 1\quad&\textbf{if }u\text{ is a leaf }\textbf{then} \\ 2\quad&\quad F(u)=K(u)F(1)+(1-K(u)-E(u))(F(fa(u))+1) \\ 3\quad&\textbf{else } \\ 4\quad&\quad F(u)=K(u)F(1)+{1-K(u)-E(u)\over D(u)}\left(F(fa)+1+\sum_{v\in son(u)}(F(v)+1)\right) \end{aligned} \]

转移有环,而如果使用高斯消元会 \(\rm TLE\),考虑直接硬解:

\(F(u)=\alpha K(1)+\beta F(fa(u))+\gamma\),那么

对于叶子节点,有

\[\begin{cases} &\alpha=K(u) \\ &\beta=1-K(u)-E(u) \\ &\gamma=1-K(u)-E(u) \end{cases} \]

对于非叶子节点,有

\[\begin{cases} &\alpha=K(u) \\ &\beta={1-K(u)-E(u)\over D(u)} \\ &\gamma={{1-K(u)-E(u)\over D(u)}}\sum_{v\in son(u)}(F(v)+1)+{1-K(u)-E(u)\over D(u)} \end{cases} \]

对于 \(\gamma\) 进行化简,有

\[\begin{aligned} \gamma=&{1-K(u)-E(u)\over D(u)}\sum_{v\in son(u)}F(v)+{1-K(u)-E(u)\over D(u)}\times D(u) \\ =&{1-K(u)-E(u)\over D(u)}\sum_{v\in son(u)}\left(\alpha_vF(1)+\beta_vF(fa(v))+\gamma_v\right)+ 1-K(u)-E(u) \\ =&{1-K(u)-E(u)\over D(u)}\sum_{v\in son(u)}\left(\alpha_vF(1)+\beta_vF(u)+\gamma_v\right)+1-K(u)-E(u) \end{aligned} \]

将这个带回 \(F(u)\) 的含参式,得到

\[\begin{aligned} &\left(1-\left({1-K(u)-E(u)\over D(u)}\right)\times ∑\beta_v\right)\times F(u) \\ =&\left(K(u)+\left({1-K(u)-E(u)\over D(u)}\right)\times ∑\alpha_v\right)\times F(1) \\ &+ {1-K(u)-E(u)\over D(u)}\times F(fa(u))\\ &+(1-K(u)-E(u)) + {1-K(u)-E(u)\over D(u)}\times ∑\gamma_v \end{aligned} \]

此时,我们可以直接算 \(\alpha_u,\beta_u,\gamma_u\)​​ 了,具体来说就是将 \(F(u)\)​​ 的系数除到右边去,然后就得到了 \(F(u)=\alpha F(1)+\beta F(fa(u))+\gamma\)​​​ 的形式的式子,并且这些系数与 \(F\)​ 无关。

对于根节点,有 \(F(1)=\alpha F(1)+\gamma\),得到

\[F(1)={\gamma_1\over 1-\alpha_1} \]

如果 \(\alpha_1\rightarrow 1\) 或者中途某一步除数为 \(0\) 就无解了。

时间复杂度 \(\mathcal (Tn)\).

叁、参考代码 ¶

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

#define NDEBUG
#include<cassert>

namespace Elaina{
    #define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
    #define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
    #define fi first
    #define se second
    #define mp(a, b) make_pair(a, b)
    #define Endl putchar('\n')
    #define mmset(a, b) memset(a, b, sizeof a)
    // #define int long long
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    template<class T>inline T fab(T x){ return x<0? -x: x; }
    template<class T>inline void getmin(T& x, const T rhs){ x=min(x, rhs); }
    template<class T>inline void getmax(T& x, const T rhs){ x=max(x, rhs); }
    template<class T>inline T readin(T x){
        x=0; int f=0; char c;
        while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
        for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
        return f? -x: x;
    }
    template<class T>inline void writc(T x, char s='\n'){
        static int fwri_sta[1005], fwri_ed=0;
        if(x<0) putchar('-'), x=-x;
        do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
        while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
        putchar(s);
    }
}
using namespace Elaina;

const int maxn=1e4;
const double eps=1e-10;

inline int compare(double x, double y){
    if(fab(x-y)<eps) return 0;
    if(x>y) return 1;
    return -1;
}

vector<int>g[maxn+5];
double K[maxn+5], E[maxn+5];
int d[maxn+5], n;
inline void add_edge(int u, int v){
    g[u].push_back(v); ++d[u];
    g[v].push_back(u); ++d[v];
}

inline void input(){
    n=readin(1);
    for(int i=1; i<=n; ++i)
        g[i].clear(), d[i]=0;
    int u, v;
    for(int i=1; i<n; ++i){
        u=readin(1), v=readin(1);
        add_edge(u, v);
    }
    int k, e;
    for(int i=1; i<=n; ++i){
        k=readin(1), e=readin(1);
        K[i]=1.0*k/100, E[i]=1.0*e/100;
    }
}

double alpha[maxn+5], beta[maxn+5], gamma[maxn+5];

bool dfs(int u, int par){
    if(d[u]==1 && u!=1){ // is a leaf
        alpha[u]=K[u];
        beta[u]=gamma[u]=1-K[u]-E[u];
        // printf("alpha %d == %.6f\nbeta %d == %.6f\ngamma %d == %.6f\n", u, alpha[u], u, beta[u], u, gamma[u]);
        return true;
    }
    double sumAlpha=0, sumBeta=0, sumGamma=0;
    for(int v: g[u]) if(v!=par){
        if(!dfs(v, u)) return false;
        sumAlpha+=alpha[v];
        sumBeta+=beta[v];
        sumGamma+=gamma[v];
    }
    double C=(1-K[u]-E[u])/d[u];
    double A=1-sumBeta*C;
    double B=K[u]+sumAlpha*C;
    double D=1-K[u]-E[u]+C*sumGamma;
    if(compare(A, 0)==0) return false;
    alpha[u]=B/A, beta[u]=C/A, gamma[u]=D/A;
    return true;
}

signed main(){
    rep(_, 1, readin(1)){
        input();
        printf("Case %d: ", _);
        if(!dfs(1, 0)) printf("impossible\n");
        else if(compare(alpha[1], 1)==0) printf("impossible\n");
        else printf("%.6f\n", gamma[1]/(1-alpha[1]));
    }
    return 0;
}

肆、关键之处 ¶

对于这种转移存在环,但是又非 \(\mathcal O(n^3)\) 的数据范围时,一种常用套路是将父节点与子节点分离开,然后设参暴力算。

posted @ 2021-07-22 11:43  Arextre  阅读(49)  评论(0编辑  收藏  举报