DP练习

Posted xishirujin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP练习相关的知识,希望对你有一定的参考价值。

马上要联赛了,我要来抱一抱DP的佛脚(QWQ)

最近膜你赛的题目的常规(dp)都不是很难推,但是优化这一方面确实不是很好,所以我来这里复(学)习一下一些常见DP优化和其他类型的DP(dalao勿D)qwq (未完待续)

1、P2059 [JLOI2013]卡牌游戏

2、P1850 换教室(期望DP)


1、P2059 [JLOI2013]卡牌游戏

这道题也是一道比较基础的 (算是) 概率dp吧。
我们首先可以来分析一下这道题目的状态,我们要明白这道题的操作流程,如果你不是很懂的话请自行那一副牌来模拟一下。
我们现在来看一下这个(dp)的状态转移的方程。
(f[i][j])表示还剩(i)个人的时候庄家向后数(j)位的时候的人获胜的概率。
所以,我们现在来考虑一下我们(f[i][])的状态一定是从(f[i-1][])转移来,所以我们现在就来讨论一下(j)的情况。
这个时候我们可以来枚举一下当(j)为庄家是所抽的牌为(k)时的情况。这时我们可以假设此时淘汰的人为(w),如果(w==j)那么这个情况就不用考虑了, (自己的没了,还玩个锤子啊)
如果,(w<j)的时候,这时候(j)的位置就变成了(j-c)
如果,(w>j)的时候,(j)的位置就变成了(i-w+j)
所以,我们的状态转移方程就可以写出来了。
[f[i][j]=f[i][j]+f[i-1][i-w+j]/m (w>j) ]
[f[i][j]=f[i][j]+f[i-1][j-w]/m (w<j) ]

code


#include< iostream >
#include< cstdio>
#include< cstring>
#include< algorithm>
#include< cmath>
using namespace std;
template< typename type>
void scan(type &x){
    type f=1;x=0;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    x*=f;
}
#define itn int
#define db double
const int N=1e5+7;
db f[1005][1005];//f[i][j]表示在还剩i个人的时候从庄家开始数的第j个人获胜的概率 
itn a[N],n,m;

int main(){
    scan(n);scan(m);
    for(itn i=1;i<=m;i++){
        scan(a[i]);
    }
    f[1][1]=1.0;
    for(itn i=2;i<=n;i++){
        for(int j=1;j<=i;j++){
            for(itn k=1;k<=m;k++){
                itn w;
                if(a[k]%i==0){
                    w=i;
                }else{
                    w=a[k]%i;
                }
                if(w>j){
                    f[i][j]+=f[i-1][i+j-w]/m;
                }else{
                    f[i][j]+=f[i-1][j-w]/m;
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        printf("%.2lf%% ",f[n][i]*100.0);
    }
    return 0;
}

回到顶部


2、P1850 换教室(期望DP)

这道题是一道期望DP的题,但是应该难度还不算太大。其实就是将计算期望的方法融入到DP式子中。
首先,我们可以来分析一下这道题,我们现在已知的是每一天的原来(c_i)和现在的教室(d_i),以及要到这个教室的路径贡献(dis[i][j])(可以提前预处理出来),还有就是我们每一次换教室成功的概率(k_i),我们就可以枚举每一次的换教室的选还是不选,然后再通过概率去进行计算期望。这个时候,我们的基本状态就可以设计出来了。
(f[i][j][0/1])表示在(i)之前的时间中有(j)个教室进行了交换,(0/1)表示这个教室选择换还是不换的期望最小值。
现在我们来考虑如何进行转移。

(f[i][j][0])时,表示这个教室我们不选择进行交换,我们来考虑一下上一个时间的状态

当上一个时间不选择交换时,贡献
[f[i-1][j][0]+dis[c[i-1]][c[i]]]
当上一个时间选择交换时,贡献
[f[i-1][j][1]+k[i-1]*dis[d[i-1]][c[i]]+(1-k[i-1])*dis[c[i-1]][c[i]]]

同理,我们来考虑一下(f[i][j][1])选择这个教室进行交换的状态

当上一个时间不选择交换时,贡献
[f[i-1][j-1][0]+k[i]*dis[c[i-1]][d[i]]+(1-k[i])+dis[c[i-1]][c[i]]]
当上一个时间选择交换时,贡献
[f[i-1][j-1][1]+k[i-1]*k[i]*dis[d[i-1]][d[i]]+(1-k[i-1])*k[i]*dis[c[i-1]][d[i]]+k[i-1]*(1-k[i])*dis[d[i-1]][c[i]]+(1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]]]
所以我们就可以把这道题解决掉了。

code


#include< iostream>
#include< cstdio>
#include< cstring>
#include< algorithm>
#include< cmath>
using namespace std;
template< typename type>
void scan(type &x){
    type f=1;x=0;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    x*=f;
}
#define itn int
#define db double
const int N=2007;
const int inf=1e9+7;
int d[N],c[N],n,m,v,e,dis[307][307];
db f[N][N][2],k[N],ans;


int main(){
    scan(n);scan(m);scan(v);scan(e);
    for(int i=1;i<=n;i++){
        scan(c[i]);
    }
    for(int i=1;i<=n;i++){
        scan(d[i]);
    }
    for(int i=1;i<=n;i++){
        scanf("%lf",&k[i]);
    }
    for(int i=1;i<=v;i++){
        for(int j=1;j< i;j++){
            dis[i][j]=dis[j][i]=inf;
        }
    }
    for(itn i=1;i<=e;i++){
        itn a,b,w;
        scan(a);scan(b);scan(w);
        dis[a][b]=min(w,dis[a][b]);
        dis[b][a]=dis[a][b];
    }
    for(int s=1;s<=v;s++){
        for(int i=1;i<=v;i++){
            for(int j=1;j=1){
                f[i][j][1]=min(f[i-1][j-1][1]+k[i-1]*k[i]*dis[d[i-1]][d[i]]+(1-k[i-1])*k[i]*dis[c[i-1]][d[i]]+k[i-1]*(1-k[i])*dis[d[i-1]][c[i]]+(1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]],f[i-1][j-1][0]+k[i]*dis[c[i-1]][d[i]]+(1-k[i])*dis[c[i-1]][c[i]]);
            }
        }
    }
    ans=inf;
    for(int i=0;i<=m;i++){
        for(int j=0;j<=1;j++){
            ans=min(ans,f[n][i][j]);
        }
    }
    printf("%.2lf",ans);
    
    return 0;
}

回到顶部


以上是关于DP练习的主要内容,如果未能解决你的问题,请参考以下文章

算法练习--- DP 求解最长上升子序列(LIS)

spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段

添加两个窗格的平板电脑布局会导致在移动设备中找不到视图(小于w600dp)

2016.2.24 dp练习

Python练习册 第 0013 题: 用 Python 写一个爬图片的程序,爬 这个链接里的日本妹子图片 :-),(http://tieba.baidu.com/p/2166231880)(代码片段

1024. 视频拼接 dp