JC的小苹果

一、题目

点此看题
Description
让我们继续JC和DZY的故事。
“你是我的小丫小苹果,怎么爱你都不嫌多!”
“点亮我生命的火,火火火火火!”
话说JC历经艰辛来到了城市B,但是由于他的疏忽DZY偷走了他的小苹果!没有小苹果怎么听歌!他发现邪恶的DZY把他的小苹果藏在了一个迷宫里。JC在经历了之前的战斗后他还剩下hp点血。开始JC在1号点,他的小苹果在N号点。DZY在一些点里放了怪兽。当JC每次遇到位置在i的怪兽时他会损失Ai点血。当JC的血小于等于0时他就会被自动弹出迷宫并且再也无法进入。
但是JC迷路了,他每次只能从当前所在点出发等概率的选择一条道路走。所有道路都是双向的,一共有m条,怪兽无法被杀死。现在JC想知道他找到他的小苹果的概率。
P.S.大家都知道这个系列是提高组模拟赛,所以这是一道送分题balabala
Input
第一行三个整数表示n,m,hp。接下来一行整数,第i个表示jc到第i个点要损失的血量。保证第1个和n个数为0。接下来m行每行两个整数a,b表示ab间有一条无向边。
Output
仅一行,表示JC找到他的小苹果的期望概率,保留八位小数。
Hint
对于100%的数据 2<=n<=150,hp<=10000,m<=5000,保证图联通。

二、解法

很容易想到 d p dp 的做法,设 d p [ i ] [ j ] dp[i][j] 为血量为 i i ,走到点 j j 的概率,答案是 i = 1 h p d p [ i ] [ n ] \sum_{i=1}^{hp} dp[i][n] ,转移如下:
d p [ i ] [ u ] = d p [ i + a [ u ] ] [ v ] d e g [ v ] dp[i][u]=\sum \frac{dp[i+a[u]][v]}{deg[v]} 其中 d e g deg 是度数,要保证 i + a [ u ] h p i+a[u]\leq hp ,现在问题也很显然,就是当 a [ u ] = 0 a[u]=0 时这个方程无法转移。

可以考虑高斯消元,每一层暴力解方程,时间复杂度 O ( n 3 h p ) O(n^3hp)

考虑优化,可以发现每次列出方程是未知数的矩阵都是一模一样的,只有常数项不一样,所以我们能否根据这个特性来减少复杂度呢?答案是可以的,我们先跑一遍高斯消元,预处理这个方程消去的方式(用哪一行消去哪一行,要乘上多少),然后直接对常数项进行操作,就可以在 O ( n 2 h p ) O(n^2hp) 的时间解决这个问题。

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define eps 1e-10
#define db double
const int N = 205;
const int M = 10005;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,hp,tot,f[N],c[N];
db ans,dp[M][N],a[N][N],b[N],d[N];
struct edge
{
    int v,next;
    edge(int V=0,int N=0): v(V) , next(N) {}
}e[M];
struct node
{
    int i,j;db t;
    node(int I=0,int J=0,db T=0): i(I) , j(J) , t(T) {}
};vector<node> g;
int cmp(db x,db y)
{
    if(x-y>eps) return 1;
    if(x-y<-eps) return -1;
    return 0;
}
void gauss()
{
    for(int i=1;i<=n;i++)
    {
        int Max=i;
        for(int r=i+1;r<=n;r++)
            if(cmp(a[Max][i],a[r][i])==-1)
                Max=r;
        swap(a[i],a[Max]);
        if(cmp(a[i][i],0)==0) continue;
        for(int j=1;j<=n;j++)
        {
            if(cmp(a[j][i],0)==0 || i==j) continue;
            db t=a[j][i]/a[i][i];
            for(int k=i;k<=n;k++)
                a[j][k]-=a[i][k]*t;
            g.push_back(node(i,j,t));
        }
    }
}
int main()
{
    n=read();m=read();hp=read();
    for(int i=1;i<=n;i++)
        c[i]=read();
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read();
        e[++tot]=edge{v,f[u]},f[u]=tot,d[u]+=1.0;
        if(u!=v) e[++tot]=edge{u,f[v]},f[v]=tot,d[v]+=1.0;
    }
    for(int i=1;i<=n;i++)
    {
        a[i][i]=1.0;
        if(c[i]) continue;
        for(int j=f[i];j;j=e[j].next)
            if(e[j].v!=n)
                a[i][e[j].v]-=1.0/d[e[j].v];
    }
    gauss();
    for(int i=hp;i>=1;i--)
    {
        memset(b,0,sizeof b);
        if(i==hp) b[1]+=1.0;
        for(int j=1;j<=n;j++)
            if(c[j] && i+c[j]<=hp)
            {
                for(int k=f[j];k;k=e[k].next)
                {
                    int v=e[k].v;
                    if(v!=n) b[j]+=dp[i+c[j]][v]/d[v];
                }
            }
        for(int j=0;j<g.size();j++)
            b[g[j].j]-=b[g[j].i]*g[j].t;
        for(int j=1;j<=n;j++)
            dp[i][j]=b[j]/a[j][j];
    }
    for(int i=1;i<=hp;i++)
        ans+=dp[i][n];
    printf("%.8lf\n",ans);
}
发布了192 篇原创文章 · 获赞 12 · 访问量 3343

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/103841841
jc