GYM 101147 K.Touristic Trip(概率DP)

23 篇文章 0 订阅

Description
有n个城市(编号0~n-1),m种明信片(编号0~m-1),当前在i城市旅游下一次去j城市旅游的概率是P[i][j],当前在i城市送第j种明信片给父母的概率是C[i][j],现在给出旅游K个城市的过程中送出的明信片的序列a[i],问旅程送出明星片满足该序列的条件下在Z城市送出该序列中第Q张明星片的概率,初始在城市0
Input
第一行一整数T表示用例组数,每组用例首先输入五个整数n,m,K,Q,Z分别表示城市数量,明星片数量,旅行的城市数,要查询明星片在序列中的编号和的城市编号,之后一个n*n矩阵A和一个n*m矩阵C,最后K个整数a[i]表示在旅游K个城市时送出的明信片(1<=n<=20,1<=m<=10,1<=K<=15,0<=Q < K,0<=Z < n)
Output
输出在送出明星片序列满足所给序列的条件下在Z城市送出第Q张明星片的概率
Sample Input
1
3 3 3 2 1
0.00 0.75 0.25
0.10 0.00 0.9
0.1 0.9 0.00
0.2 0.3 0.5
0.1 0.01 0.89
0.2 0.3 0.5
0 1 2
Sample Output
0.889
Solution
条件概率,P(B|A)=P(AB)/P(A)
dp[i][j]表示在旅行的第i个城市是城市j且送出的是第a[i]种的明星片的概率,则dp[0][a[0]]=C[0][a[0]],对于i从1到Q转移,转移方程dp[i][j]+=dp[i-1][k]*P[k][j]*C[j][a[i]],之后,求P(AB)需要的是dp[Q][Z],求P(B)需要的是dp[Q][j] (0<=j<=n-1),所以令dpp[Q][Z]=dp[Q][Z],dpp[Q][j]=0(j!=Z),之后dpp和dp按上面同样的转移方程从i=Q-1到K-1同时进行转移,最后P(AB)=sum{dpp[K-1][j]},P(B)=sum{dp[K-1][j]},0<=j<=n-1,两者相除即为答案
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
int T,n,m,K,Q,Z,a[22],flag[22];
double P[22][22],C[22][22],dp[22][22],dpp[22][22];
int main()
{
    freopen("trip.in","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d%d",&n,&m,&K,&Q,&Z);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%lf",&P[i][j]);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                scanf("%lf",&C[i][j]);
        memset(flag,0,sizeof(flag));
        for(int i=0;i<K;i++)scanf("%d",&a[i]);
        memset(dp,0,sizeof(dp));
        memset(dpp,0,sizeof(dpp));
        dp[0][0]=C[0][a[0]];
        for(int i=1;i<=Q;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    dp[i][j]+=(dp[i-1][k]*P[k][j]*C[j][a[i]]);
        dpp[Q][Z]=dp[Q][Z];
        for(int i=Q+1;i<K;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    dp[i][j]+=(dp[i-1][k]*P[k][j]*C[j][a[i]]),dpp[i][j]+=(dpp[i-1][k]*P[k][j]*C[j][a[i]]);
        double ans1=0,ans2=0;
        for(int i=0;i<n;i++)
            ans1+=dp[K-1][i],ans2+=dpp[K-1][i];
        printf("%.3f\n",ans2/ans1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值