景区路线规划(概率dp)

题目描述

美团旅行团队最近打算推出一项新服务,为景区的各个景点规划游览路线,提升游客满意度。其中一个重要的问题是对于一个景区道路网,求出游客的满意度的期望值。基于用户的喜好差异,我们需要对男性游客和女性游客的满意度分别计算。
景区被描述成一张n个点、m条边的无向图(无重边,无自环)。每个点代表一个景点,第i个景点游览需要耗费ci分钟,会让男性游客和女性游客的满意度分别增加h1i和h2i(满意度初始值都为0)。每条边代表一条路,第i条边连接编号为xi,yi的两个景点,从景点xi走到yi和从yi走到xi的时间都是ti分钟。
每个游客在景区中最长可以游览k分钟,最开始会随机的通过不同大门进入到一个景点开始游览,每游览完一个项目,游客会等概率随机选择一个可以从当前景点直达且来得及游览的景点作为下一个游览目标(已经游览过的景点也会因为有各种新活动而让游客再次考虑,所以我们这里不区分景点是否已经游览过)。如果游览完一个景点后,周围没有来得及游览的景点,本次游玩就结束了。
请你分别计算小y和妹子在游玩结束后开心度的期望。

输入描述:

第一行给出三个空格隔开的整数,分别表示n, m, k(0 < n ≤ 100, 1 * 60 ≤ k ≤ 8 * 60)
接下来的n行,每行三个空格隔开的整数,分别表示ci, h1i, h2i (10 ≤ ci ≤ 60,0 < h1i, h2i ≤ 100)
接下来的m行,每行三个空格隔开的整数,分别表示xi, yi, ti (0 < ti ≤ 15)

输出描述:

两个用空格隔开的实数,分表表示小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

题目思路:

普通概率dp题,分别求男生和女生的期望值,dp[i][j].first表示在i分钟j点的期望,dp[i][j].second表示概率。
最后如果一个地点也不能走了,要把值赋给dp[k][j].first,最后统计dp[k][i].first的和。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,k,c[102],h[3][101];
pair<double,double> dp[500][101];
vector< pair<int,int> > v[101];
double ans[3];
void find_ans(int x)
{
    memset(dp,0,sizeof(dp));
    for(int i = 1;i<=n;i++)
    {
        dp[c[i]][i].first = double(h[x][i])/n;
        dp[c[i]][i].second = 1.0/n;
    }
    for(int i = 1;i<k;i++)
    {
        for(int j = 1;j<=n;j++)
        {
            int flag = 0;
            int num = 0;
            for(int t = 0;t<v[j].size();t++)
            {
                int p = v[j][t].first;
                int time = v[j][t].second+c[v[j][t].first];
                if(i+time<=k)
                    num++;
            }
            for(int t = 0;t<v[j].size();t++)
            {
                int p = v[j][t].first;
                int time = v[j][t].second+c[v[j][t].first];
                if(i+time<=k&&dp[i][j].first)
                {
                    flag = 1;
                    dp[i+time][p].first+=dp[i][j].first*double(1.0/num)+h[x][p]*dp[i][j].second*double(1.0/num);
                    dp[i+time][p].second+=dp[i][j].second*double(1.0/num);
                }    
            }
            if(!flag)
            {
                dp[k][j].first+=dp[i][j].first;
                dp[k][j].second+=dp[i][j].second;
            }
            
        }
    }
    for(int i = 1;i<=n;i++)
        ans[x]+=dp[k][i].first;
}
int main()
{
    int a1,a2,a3;
    cin>>n>>m>>k;
    for(int i = 1;i<=n;i++)
        cin>>c[i]>>h[1][i]>>h[2][i];    
    for(int i = 1;i<=m;i++)
    {
        cin>>a1>>a2>>a3;
        v[a1].push_back(make_pair(a2,a3));
        v[a2].push_back(make_pair(a1,a3));
    }
    find_ans(1);
    find_ans(2);
    printf("%.5lf %.5lf",ans[1],ans[2]);
    return 0;
}

欢迎关注微信公众号:Java后台开发

致力于分享原创计算机与软件开发知识及SSM、Spring cloud、Redis、微服务等Java后端开发技术
公众号里还有很多开发工具及学习资料

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值