概率 · dp练习 (16.04.16)

由于前辈出的三道题中有一道是自己以前写过的,且写过博文,所以本文就再找了一道和概率相关的简单题来凑数。

UVA - 12230 Crossing Rivers

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3382
大意:一人从西岸走到东岸,之间有许多条河,人在陆地上的行走速度是1。河的参数:p,l,v 分别表示河的西岸距离起点陆地的距离,河的宽度,船儿在河里的行驶速度。
分析:船儿在河里的行驶极端状况:
(1)
|         |
| —> |
|         |
(2)
| —> |
| <— |
| —-> |
所以平均的行驶时间是 2l/v
结果就是: 2livi+Dli

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int n,d;
    int ca=0;
    while(~scanf("%d%d",&n,&d)){
        if(n==0 && d==0) break;
        double ans=0;
        int p,l,v;
        for(int i=0;i<n;i++){
            scanf("%d%d%d",&p,&l,&v);
            ans=ans+2.0*l/v-l;
        }
        ans=ans+d;
        printf("Case %d: %.3lf\n\n",++ca,ans);
    }
    return 0;
}

hdu 4405 Aeroplane chess

http://acm.hdu.edu.cn/showproblem.php?pid=4405
大意:有N+1个格子,从0开始,每一次执色子,1—6个点数,向前跳跃,直到>=n点,其中还有飞跃点对ai,bi,表示从ai能直接到bi,求解掷色子的个数的期望。
分析:for k=1–>6 : dp[i]=(dp[i+k]×16)+1
模拟跳跃,即程序中的continue。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e3+10,M=2e5+20;
struct node{
    int s,e;
}f[N];
double dp[M];
int main()
{
    //freopen("cin.txt","r",stdin);
    int n,m;
    while(cin>>n>>m){
        if(n==0&&m==0) break;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<m;i++)  scanf("%d%d",&f[i].s,&f[i].e);
        for(int i=n-1;i>=0;i--){
            bool tag=0;
            for(int j=0;j<m;j++){
                if(f[j].s==i){ dp[i]=dp[f[j].e]; tag=1; break; }
            }
            if(tag) continue;
            for(int j=i+1;j<=i+6;j++) dp[i]+=dp[j]*1.0/6;
            dp[i]++;
        }
        printf("%.4lf\n",dp[0]);
    }
    return 0;
}

hdu 5001 walk

http://acm.hdu.edu.cn/showproblem.php?pid=5001
大意:对于一幅无向图,从任意一个点出发走k步后求解不经过i结点的概率。
分析:设 dp[i][j] 的意义是经过i步后到达j的概率,那么针对vector的前向星暴力求解即可。
参照网上代码修改AC后的疑惑:
我觉得这题很奇葩,如果它是问最后第d步没包含i点的话,最开始为什么一定要跳过i点?如果它是问每一步均不包含i点,那么为什么最后求解d步到达其他点的概率就是答案?
——————————————————
16.04.25更新: 有些点经过d步不会经过它。

//bad code:      
       for(int i=1;i<=n;i++){
            memset(dp,0,sizeof(dp));
            for(int j=1;j<=n;j++) dp[0][j]=1.0/n;
            for(int j=1;j<=d;j++){
                for(int k=1;k<=n;k++){
                    if(k==i) continue;
                    int len=edge[k].size();
                    for(int h=0;h<len;h++){
                        int v=edge[k][h];
                        dp[j][v]+=dp[j-1][v];
                        dp[j][v]+=dp[j-1][k]*1.0/len;
                    }
                }
            }
            printf("%.10lf\n",1-dp[d][i]);
        }

对比:

//AC:
        for(int i=1;i<=n;i++){
            memset(dp,0,sizeof(dp));
            for(int j=1;j<=n;j++) dp[0][j]=1.0/n;
            for(int j=1;j<=d;j++){
                for(int k=1;k<=n;k++){
                    if(k==i) continue;
                    int len=edge[k].size();
                    for(int h=0;h<len;h++){
                        int v=edge[k][h];
                        dp[j][v]+=dp[j-1][k]*1.0/len;
                    }
                }
            }
            double ans=0;
            for(int j=1;j<=n;j++) if(j!=i) ans=ans+dp[d][j];
            printf("%.10lf\n",ans);
        }

完整代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
double dp[10005][55];
int main()
{
    //freopen("cin.txt","r",stdin);
    int t;
    cin>>t;
    while(t--){
        int n,m,d;
        scanf("%d%d%d",&n,&m,&d);
        vector<int> edge[55];
        for(int i=0;i<m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            edge[a].push_back(b);
            edge[b].push_back(a);
        }
        for(int i=1;i<=n;i++){
            memset(dp,0,sizeof(dp));
            for(int j=1;j<=n;j++) dp[0][j]=1.0/n;
            for(int j=1;j<=d;j++){
                for(int k=1;k<=n;k++){
                    if(k==i) continue;
                    int len=edge[k].size();
                    for(int h=0;h<len;h++){
                        int v=edge[k][h];
                        dp[j][v]+=dp[j-1][k]*1.0/len;
                    }
                }
            }
            double ans=0;
            for(int j=1;j<=n;j++) if(j!=i) ans=ans+dp[d][j];
            printf("%.10lf\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值