LibreOJ #6178. 「美团 CodeM 初赛 Round B」景区路线规划【概率DP】

「美团 CodeM 初赛 Round B」景区路线规划

问题描述

游乐园被描述成一张 n 个点, m 条边的无向图( 无重边, 无自环) 。 每个点代表一个娱乐项目, 第 i 个娱乐项目需要耗费 ci 分钟的时间, 会让小 y 和妹子的开心度分别增加 h1(i), h2(i), 他们俩初始的开心度都是 0 。 每条边代表一条路, 第 i 条边连接编号为 x(i), y(i)的两个娱乐项目, 从 x(i)走到 y(i)或者从 y(i)走到 x(i)耗费的时间都是 t(i)分钟。
小 y 和妹子预计在游乐园里玩 k 分钟。 最开始的时候, 小 y 和妹子会等概率的随机选择一个娱乐项目开始玩, 每玩完一个项目后, 小 y 和妹子会等概率的随机选择一个可以从当前项目直达的且来得及玩的项目作为下一个项目。
如果玩完一个项目后周围没有可以直达的且来得及玩的项目, 小 y 和妹子就会提前结束游玩。 请你分别计算小 y 和妹子在游玩结束后开心度的期望。

输入格式

第一行给出三个空格隔开的整数, 分别表示 n,m,k;
接下来的 n 行, 每行三个空格隔开的整数, 分别表示 c(i),h1(i),h2(i);
接下来的 m 行, 每行三个空格隔开的整数, 分别表示 x(i),y(i),t(i)

输出格式

两个用空格隔开的实数, 分表表示小 y 和妹子开心度的期望, 精确到小数点后 5 位。

样例

输入样例

5 4 60
25 12 83
30 38 90
16 13 70
22 15 63
50 72 18
2 1 7
3 1 7
4 3 1
5 3 10

输出样例

39.20000 114.40000

数据范围

0<n100 0 < n ≤ 100
1×60k8×60 1 × 60 ≤ k ≤ 8 × 60
10c(i)60 10 ≤ c ( i ) ≤ 60
0<h1(i),h2(i)100 0 < h 1 ( i ) , h 2 ( i ) ≤ 100
0<ti150 0 < t i ≤ 150

题解

让我们求期望,也就是相邻路径上的价值/路径总数,没问题吧!
但是我们不知道时间,那么就用的DP了,枚举时间,然后这么做就OK了。
f[i][t]it f [ i ] [ t ] 表 示 第 i 个 点 还 有 t 个 时 刻 的 最 优 解 。
转移方程: f[son][t+wi,son+Ci]+=f[i][j] f [ s o n ] [ t + w i , s o n + C i ] + = f [ i ] [ j ] 可 行 的 边 数

代码如下

#include<cstdio>
#define MAXN 105
#define MAXE 200005
#define LL long long
using namespace std;
int n,m,K,T[MAXN],H[MAXN][2];
double Ans1,Ans2,F[MAXN][505];
int tot,lnk[MAXN],nxt[MAXE],son[MAXE],W[MAXE];
void Add(int x,int y,int z){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;W[tot]=z;}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=n;i++) scanf("%d%d%d",&T[i],&H[i][0],&H[i][1]),F[i][T[i]]=(double)1/n;
    for(int i=1;i<=m;i++){
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        Add(x,y,w),Add(y,x,w);
    }
    for(int t=0;t<=K;t++)
    for(int i=1,tmp=0;i<=n;i++,tmp=0){
        for(int j=lnk[i];j;j=nxt[j]) tmp+=(t+W[j]+T[son[j]]<=K);//找可行边
        for(int j=lnk[i];j;j=nxt[j]) if(t+W[j]+T[son[j]]<=K) F[son[j]][t+W[j]+T[son[j]]]+=F[i][t]/tmp;
    }
    for(int i=1;i<=n;i++)
    for(int t=2;t<=K;t++) Ans1+=(double)H[i][0]*F[i][t],Ans2+=(double)H[i][1]*F[i][t];
    printf("%.5lf %.5lf\n",Ans1,Ans2);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值