动规 - 概率DP

学习资料

  1. 百度百科 - 期望
  2. 浅谈概率期望 By 朝阳的二愣子
  3. 概率DP/期望DP总结 By myjs999
  4. 动态规划 —— 概率 DP 与期望 DP By Alex_McAvoy
  5. 【概率期望动态规划】 By 大米饼
  6. 【整理】简单的数学期望和概率DP By nimphy

练习题

luogu 1850 NOIP2016 换教室

传送门:luogu1850
我的题解:luogu1850 换教室

/*************************
User:Mandy.H.Y
Language:c++
Problem:luogu1850
Algorithm: 
*************************/

#include<bits/stdc++.h>

using namespace std;

const int maxn = 2005;
const int maxv = 305;
const int maxe = 90005;

int n,m,v,e,size;
int c[maxn],d[maxn];
double k[maxn],dp[maxn][maxn][3];
int g[maxv][maxv];

struct Edge{
	int v,nt,w;
}edge[maxe << 1];

template<class T>inline void read(T &x){
	x = 0;bool flag = 0;char ch = getchar();
	while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
	while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
	if(flag) x = -x;
}

template<class T>void putch(const T x){
	if(x > 9) putch(x / 10);
	putchar(x % 10 | 48);
}

template<class T>void put(const T x){
	if(x < 0) putchar('-'),putch(-x);
	else putch(x);
}

void file(){
	freopen("1850.in","r",stdin);
	freopen("1850.out","w",stdout);
}

void readdata(){
	memset(g,0x3f3f3f3f,sizeof(g));
	read(n);read(m);read(v);read(e);
	for(int i = 1;i <= v; ++ i) g[i][i] = 0;
	for(int i = 1;i <= n; ++ i) read(c[i]);
	for(int i = 1;i <= n; ++ i) read(d[i]);
	for(int i = 1;i <= n; ++ i) scanf("%lf",&k[i]);
	for(int i = 1;i <= e; ++ i) {
		int u,v,w;
		read(u);read(v);read(w);
		g[u][v] = min(g[u][v],w);
		g[v][u] = g[u][v];
	}
}

void Floyd(){
	for(int l = 1;l <= v; ++ l)
	for(int i = 1;i <= v; ++ i)
	for(int j = 1;j <= v; ++ j){
		if(g[i][l] != 0x3f3f3f3f && g[l][j] != 0x3f3f3f3f)
			if(g[i][l] + g[l][j] < g[i][j]) g[i][j] = g[i][l] + g[l][j];
	}
}

void work(){
	
	Floyd();
	
	for(int i = 2;i <= n; ++ i){
		
		int u1 = c[i - 1],u2 = d[i - 1];
		int v1 = c[i],v2 = d[i];
		
		dp[i][0][0] = dp[i - 1][0][0] + g[u1][v1];
		
		for(int j = 1;j <= m; ++ j){
			
			dp[i][j][0] = min(dp[i - 1][j][0] + g[u1][v1],
							  dp[i - 1][j][1] + 
							  k[i - 1] * g[u2][v1] + 
							  (1 - k[i - 1]) * g[u1][v1]);
			
			dp[i][j][1] = dp[i - 1][j - 1][0] + 
						  k[i] * g[u1][v2] + 
						  (1 - k[i]) * g[u1][v1];
			if(j > 1) dp[i][j][1] = min(dp[i][j][1],dp[i - 1][j - 1][1] + 
													k[i - 1] * k[i] * g[u2][v2] + 
													k[i - 1] * (1 - k[i]) * g[u2][v1] +
													(1 - k[i - 1]) * k[i] * g[u1][v2] +
													(1 - k[i - 1]) * (1 - k[i]) * g[u1][v1]);
		
		}
	}
	double ans = 2000000000.0;
	for(int i = 0;i <= m; ++ i) {
		ans = min(ans,dp[n][i][0]);
		if(i > 0) ans = min(ans,dp[n][i][1]);
	}
	
	printf("%.2lf",ans);
}

int main(){
//	file();
	readdata();
	work();
	return 0;
}

HDU4576 Robot

传送门:hdu4576
Problem Description
Michael has a telecontrol robot. One day he put the robot on a loop with n cells. The cells are numbered from 1 to n clockwise.

在这里插入图片描述

At first the robot is in cell 1. Then Michael uses a remote control to send m commands to the robot. A command will make the robot walk some distance. Unfortunately the direction part on the remote control is broken, so for every command the robot will chose a direction(clockwise or anticlockwise) randomly with equal possibility, and then walk w cells forward.
Michael wants to know the possibility of the robot stopping in the cell that cell number >= l and <= r after m commands.

Input
There are multiple test cases.
Each test case contains several lines.
The first line contains four integers: above mentioned n(1≤n≤200) ,m(0≤m≤1,000,000),l,r(1≤l≤r≤n).
Then m lines follow, each representing a command. A command is a integer w(1≤w≤100) representing the cell length the robot will walk for this command.
The input end with n=0,m=0,l=0,r=0. You should not process this test case.

Output
For each test case in the input, you should output a line with the expected possibility. Output should be round to 4 digits after decimal points.

Sample Input
3 1 1 2
1
5 2 4 4
1
2
0 0 0 0

Sample Output
0.5000
0.2500

翻译及题解:hdu 4576 Robot

/***********************
User:Mandy.H.Y 
Language:c++
Problem:hdu4576
Algorithm:
************************/

//一个概率 + 环形的背包? 

#include<cstdio>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<cstring>

using namespace std;

const int maxn = 205;
const int maxm = 1e6 + 5;

int n,m,l,r;
double f[2][maxn],ans = 0;

template<class T>inline void read(T &x){
    x = 0;bool flag = 0;char ch = getchar();
    while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
    if(flag) x = -x;
}

template<class T>void putch(const T x){
    if(x > 9) putch(x / 10);
    putchar(x % 10 | 48);
}

template<class T>void put(const T x){
    if(x < 0) putchar('-'),putch(-x);
    else putch(x);
}

void file(){
    freopen("4576.in","r",stdin);
    freopen("4576.out","w",stdout);
}

int get(int x){
    if(x < 1) return x + n;
    if(x > n) return x - n;
    return x;
}

void work(){
    memset(f,0,sizeof(f));//记得清零 
    f[0][1] = 1;
    int cur = 1;ans = 0; 
    for(int i = 1;i <= m; ++ i) {
        int w;read(w);w %= n;//要对n取模,防止溢出 
        for(int i = 1;i <= n; ++ i){
            f[cur][i] = f[cur ^ 1][get(i - w)] * 0.5;
            f[cur][i] += f[cur ^ 1][get(i + w)] * 0.5;
        }
        cur ^= 1;
    }
    cur ^= 1;
    for(int i = l;i <= r; ++ i) ans += f[cur][i];
}

int main(){
    
//    file();

    while(scanf("%d%d%d%d",&n,&m,&l,&r)){
        if((!n) && (!m) && (!l) && (!r)) break;
        work();
        printf("%.4lf\n",ans);
    }
    
    return 0;
}

MZOJ #78 小象涂色

题目及分析:MZOJ #78 小象涂色

/**************************
User:Mandy.H.Y
Language:c++
Problem:elephant
Algorithm:
**************************/

#include<bits/stdc++.h>

using namespace std;

const int maxn = 55;

int t,n,c,k;
int sum[maxn];
double cur[maxn][105];
double b[105]; 

char *TT,*mo,but[(1 << 15) + 2];
#define getchar() ((TT == mo && (mo = ((TT = but) + fread(but,1,1 << 15,stdin)), TT == mo)) ? -1 : *TT++)
template<class T>inline void read(T &x){
    x = 0;bool flag = 0;char ch = getchar();
    while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
    if(flag) x = -x;
}

template<class T>void putch(const T x){
    if(x > 9) putch(x / 10);
    putchar(x % 10 | 48);
}

template<class T>void put(const T x){
    if(x < 0) putchar('-'),putch(-x);
    else putch(x);
}

void file(){
    freopen("elephant.in","r",stdin);
    freopen("elephant.out","w",stdout);
}

void readdata(){
    read(n);read(c);read(k);
    memset(sum,0,sizeof(sum));
    memset(cur,0,sizeof(cur));
    memset(b,0,sizeof(b));
}

void work(){
    readdata();
    double color = ((double)1.0 / (double)c);
    for(int z = 1;z <= k; ++ z){
        int l,r;
        read(l);read(r);
        sum[l]++;
        sum[r+1]--;
    }
    
    for(int i = 1;i <= n; ++ i) sum[i] += sum[i-1];
    cur[0][1] = 1;//初始都是颜色1 
    for(int i = 1;i <= k; ++ i){
        for(int j = 0;j < c; ++ j){
            cur[i][j] = cur[i - 1][j] * 0.5;
        }
        for(int j = 0;j < c; ++ j){
            for(int x = 0;x < c; ++ x){
                cur[i][j * x % c] += cur[i-1][j] * 0.5 * color;
            }
        }
    }
    
    double ans = 0;
    for(int i = 1;i <= n; ++ i){
        for(int j = 0;j < c; ++ j){
            ans += cur[sum[i]][j] * j;
        }
    }
    printf("%.9lf\n",ans);
}

int main(){
//    file();
    read(t);
    while(t --) 
        work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值