实验一 动态规划算法

问题描述:

小明想要在王者荣耀游戏里晋升一个段位,假设他一共需打了n场比赛,且必须成功赢得至少70%的场次才能成功晋升。假设每场比赛小明获胜的概率分别=3为p1,p2,…,pn,请帮他算出成功晋级段位的概率是多少?

输入:
参数1:整数num(0<= num <=1000),表示比赛的场数。
参数2:整数数组p[num] = {p1,p2,…,pnum},其中pi表示小明有pi%的概率赢得第i场比赛。(0 <=pi <= 100)

输出:
成功晋级段位的概率,保留小数点后5位,最后结果四舍五入。

分析

这个问题可以看作:
先求解小明进行i场比赛并且赢了j场的概率
然后再求i=num,j>=num0.7(num0.7向上取整)时的结果

运用我们刚刚学的DP四步骤:

关于DP四步骤可以看动态规划(Dynamic Programming)入门

确定状态

  1. 最后一步:在进行了i场比赛后赢了j场
  2. 子问题:当第i场输了的时候,那么在前i-1场比赛,共赢了j场;当第i场赢了的时候,那么在前i-1场比赛,共赢了j-1场.

状态:设f[i][j]表示在进行了i场比赛后赢了j场的概率

转移方程

这里要分两种情况:
当j=0时,f[i][j]=f[i-1][0]*(1-p[i])
当j>0时,f[i][j]=f[i-1][j]*(1-p[i])+f[i-1][j-1]p[i]

初始条件和边界情况

初始条件:
f[0][0]=1、f[k][k]=p1*p2…pk

计算顺序

DP的目的是利用历史记录,不重复计算,所以,我们先枚举j的情况,再枚举i的情况。

代码实现:

package algorithm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


public class DPSolution {
    
    

	public static double probability(int[] p,int num) {
    
    
		double pass=0.0d;//晋级的概率
	
		double[][] f=new double[num+1][num+1];
		
		//初始条件设定,包括f[0][0]=1,以及f[k][k]=p[1]*p[2]...*p[k]
		f[0][0]=1.0d;
		for(int i=1;i<=num;++i) {
    
    
			f[i][i]=f[i-1][i-1]*0.01d*p[i-1];
		}
		
		for(int j=0;j<=num-1;++j) {
    
    
			for(int i=j+1;i<=num;++i) {
    
    
				if(j==0) {
    
    
					f[i][0]=f[i+j-1][0]*(1-p[i-1]*0.01d);//j=0时的转移方程
				}
				else {
    
    
					f[i][j]=f[i-1][j]*(1-p[i-1]*0.01d)+f[i-1][j-1]*p[i-1]*0.01d;//j>0时的转移方程
				}
			}
		}
		
		int k=(int)Math.ceil(num*0.7);//向上取整
		for(int i=k;i<=num;++i) {
    
    
			pass+=f[num][i];
		}
		//将返回值pass保留5位小数,同时四舍五入
		pass*=100000;
		pass+=0.5;
		pass=(int)(pass)/100000.0;
		return pass;
	}
	
	public static void main(String[] args) throws IOException{
    
    
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int num = 0;
		String str = null;
	    num= Integer.parseInt(br.readLine());
		str = br.readLine();		
		br.close();
		int[] p = new int[num];
		String[] strArray = str.split(" ");	
		for (int i = 0; i < num; i++) {
    
    
			p[i] = Integer.parseInt(strArray[i]);
		}
		double result=probability(p,num);
		System.out.println(result);

	}

}

分析

输入规模大小:序列p长度num,此处记为n
基本操作次数:根据递推式计算f[i][j]
输入情况:只与问题的规模有关,和问题的输入好坏无关
时间复杂度:算法是非递归的,直接累加求和就可以得到其时间复杂度为O(n2)
空间复杂度:额外空间为O(n2)(数组大小)

猜你喜欢

转载自blog.csdn.net/idler123/article/details/121055439