[机房测试]变异大老鼠

Description

给一棵树,逃犯初始在根,可以在每个点安一些人,安排 (j) 个人会有 (p_{u,j}) 的概率抓住逃犯。逃犯如果在一个节点没被抓住,就会等概率前往一个儿子,没有儿子逃犯就逃跑了。现在需分配这 (K) 个人,使得逃犯被抓住的概率最大。

Solution

本来是一个图的,要求出最短路径树才是上述题意,但没什么意思,所以省了。大样例是真的水。

很显然是一个树形dp,考虑 (dp_{u,k}) 表示逃犯当前在 (u),该子树一共安排 (k) 个人,能得到的最大概率。枚举当前节点分配多少人,就有

[dp_{u,k}=maxlimits_{0leq jleq k} {p_{u,j}+frac{1-p_{u,j}}{d}max{sum_{r_1+r_2+dots+r_d=k-j}dp_{v,r}}} ]

容易发现后面是一个背包,可以预处理出来,记为 (f_{k-j})。那么 (dp) 就可以直接暴力更新了。

#include<stdio.h>
#include<algorithm>
#include<queue>
 
typedef double db;
 
using namespace std;
 
inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}
 
const int N=3e2+7;
const int M=3e4+7;
 
int n,m,K;
 
struct E{
    int next,to,dis;
}e[M<<1];
 
struct Node{
    int pos,val;
    Node(int pos_=0,int val_=0):pos(pos_),val(val_){}
    bool operator <(const Node &X) const{return val>X.val;}
};
 
bool vis[N];
priority_queue<Node> Q;
int dis[N],fa[N],cnt=0,head[N];
 
inline void add(int id,int to,int w=0){
    e[++cnt]=(E){head[id],to,w};
    head[id]=cnt;
    e[++cnt]=(E){head[to],id,w};
    head[to]=cnt;
}
 
db dp[N][N],f[N],p[N][N];
 
void dfs(int u){
    int tot=0;
    for(int i=head[u];i;i=e[i].next)
        if(e[i].to!=fa[u]) dfs(e[i].to),tot++;
    for(int i=0;i<=K;i++) f[i]=0;
    for(int i=head[u];i;i=e[i].next){
        const int v=e[i].to;
        if(v==fa[u]) continue;
        for(int j=K;j;j--)
            for(int k=1;k<=j;k++)
                f[j]=max(f[j],f[j-k]+dp[v][k]);
    }
    if(tot){
        for(int i=1;i<=K;i++)
            for(int j=0;j<=i;j++)
                dp[u][i]=max(dp[u][i],p[u][j]+(1-p[u][j])/tot*f[i-j]);
    }else for(int i=1;i<=K;i++) dp[u][i]=p[u][i];
}
 
int main(){
    n=read(),m=read(),K=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        add(u,v,read());
    }
    for(int i=1;i<=n;i++) dis[i]=1<<30;
    dis[1]=0; Q.push(Node(1,0));
    while(!Q.empty()){
        Node t=Q.top(); Q.pop(); int u=t.pos;
        if(vis[u]) continue; else vis[u]=1;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].dis){
                dis[v]=dis[u]+e[i].dis;
                fa[v]=u; if(!vis[v]) Q.push(Node(v,dis[v]));
            }
        }
    }
    cnt=0; for(int i=1;i<=n;i++) head[i]=0;
    for(int i=2;i<=n;i++) add(i,fa[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=K;j++) scanf("%lf",&p[i][j]);
    dfs(1); printf("%.6lf",dp[1][K]);
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/15377071.html