动态规划(求中位数与概率问题)

动态规划(求中位数与概率问题)

问题:
1、设A和B都是从小到大已经排好序的n个不等的整教构成的数组, 如果把A和B合并后的数组记作C,设计一个算法找出c的中位教。
2、2、一个实验可得出n个不同的值分别用数xx,x表示已知x,出现的概率是p,,i=2…n,且所有概率之和等于10试设计一个算法找到值x;,使得所有小于x,的值出现的概率之和不超过1/2,且所有大于x的值出现的概率之和也不超过1/2。例如,实验结果为: x=2x=lx=4x.=3.x,=s,出现的概率依次是: p=0.2,D2 =04,p;=0.1,p.=01,p; =02,那么x就是所求的值。比x小的数只有xz ,它的概率是0.45比x的大的数有x,,x,x,它们的概率之和是0.4。
实现代码:

  1. 动态规划算法求两组数中位数
// 两个长度不相等的有序数组寻找中位数
#include <stdio.h>
#include <iostream>
using namespace std; 
double Find_Media(int a[] , int lengtha , int b[] , int lengthb)
{
	int mida = lengtha/2;
	int midb = lengthb/2;
	int l = (mida <= midb) ? mida : midb;  // 数组不一样长的时候,保证两边去掉的长度一致 
	if(lengtha == 1)
	{
		if(lengthb % 2 == 0)  // 数组a与b中位数位置决定了最后的结果 
		{
			if(a[0] >= b[midb])
				return b[midb];
			else if(a[0] <= b[midb-1])
				return b[midb-1];
			else return a[0];
		}
		else return (double)(a[0]+b[midb])/2;
	}
	else if(lengthb == 1)
	{
	// 对测试情况2的处理
		if(lengtha % 2 == 0)
		{
			if(b[0] >= a[mida])
				return a[mida];
			else if(b[0] <= a[mida-1])
				return a[mida-1];
			else return b[0];
		}
		else
			return (double)(b[0]+a[mida])/2;
	}
	if(a[mida] == b[midb]) {  // 两个数组的中位数相等则找到 
	/*避免类似2323的情况出现*/ 
	 if (lengtha %2==0 && lengthb%2 ==0){
	 	if (a[mida-1]<b[midb-1]){
	 		return (double)(b[midb-1]+a[midb])/2;
		 }else  return (double)(a[mida-1]+b[midb])/2;
	 }else
		return a[mida];
	}
	else if(a[mida] < b[midb])  // 不等则递归,直至某一方的数组长度变为1 
		return Find_Media(&a[mida] , lengtha-l , &b[0] , lengthb-l);
	else
		return Find_Media(&a[0] , lengtha-l , &b[midb] , lengthb-l);
}
// 给出三组测试用例,分别为三种情况
int main(){
// test1:两个数组长度一致都为偶数
	int a[] = {1,2,3,4,5};
	int b[] = {4,6,7,8,9};
	int lena = sizeof(a)/sizeof(a[0]);
	int lenb = sizeof(b)/sizeof(b[0]);
	cout<<Find_Media(a, lena, b, lenb)<<endl;
	cout<<"---------------------------"<<endl;
// test2:按照分组最后的中位数为3,但是实际为2.5,所以代码中加了最此类情况的处理
	int c[] = {1,2,3,4};
	int d[] = {1,2,3,4};
	int lenc = sizeof(c)/sizeof(c[0]);
	int lend = sizeof(d)/sizeof(d[0]);
	cout<<Find_Media(c, lenc, d, lend)<<endl;
	cout<<"---------------------------"<<endl;
test3:两个数组长度不一致
	int e[] = {1,3,5,7,9};
	int f[] = {2,4,5,8};
	int lene = sizeof(e)/sizeof(e[0]);
	int lenf = sizeof(f)/sizeof(f[0]);
	cout<<Find_Media(e, lene, f, lenf)<<endl;
}

执行结果:
问题1执行结果
问题2:求一个数使得左右两边的概率都小于0.5
采取的算法是寻找第K小的思想,函数多加入了两个参数K1与K2用于记录每一次查找后的左右两边的概率和,避免重复计算,提高效率。

// 求一组数中的目标值,满足左右两边的概率和小于0.5
#include<iostream>
#include<map> 
using namespace std;

map<int, double> p;  // 按照键值对存储数据 
void findK(int a[], int low ,int high, double k1, double k2){
	int i = low, j = high;   //把待排序数组元素的第一个和最后一个下标分别赋值给i,j,使用i,j进行排序;
	int tmp = a[low]; //将待排序数组的第一个元素作为哨兵
	double suml=0,sumr=0;   // 记录左右两边的概率和  
	if(low < high){                   
	  while(i<j){
		while(i<j && a[j] >= tmp){ // 从右侧开始判断累计概率 
		    sumr+=p[a[j]];
			j--; 
		 }
		  if(i<j)  a[i] = a[j]; // 交换不满足条件的 
		  while(i<j && a[i] <= tmp){  //换成左侧下标为i的元素开始 
		  	  suml+=p[a[i]];
			  i++;     
		 }
		  if(i<j) a[j] = a[i];  //交换不符合条件的 
		}
	    a[i] = tmp;   //完成一次排序,把哨兵赋值到下标为i的位置,即前面的都比它小,后面的都比它大
	   if(suml+k1< 0.5 & sumr+k2<0.5){  // 满足条件
	   	   cout<<a[i]<<endl;
	   	   cout<<"左边概率和: "<<suml+k1<<"\n"<<"右边概率和: "<<sumr+k2<<endl;
	   }
       else if(suml+k1>0.5){    // 左边的概率和大 
       	 k2+=sumr+p[a[i]];   // 保存右边的概率和,每次递归都大则累加 
       	 k1=0;          //  左边为0 重新求取 
       	 findK(a,low,i-1,k1,k2);
	   }
	   else if(sumr+k2>0.5){    // 右边概率和大 
	   	k1+=suml+p[a[i]];     //  保存整个左边的概率和,递归一只大则一直加 
	   	k2=0;     // 此时右边重新求取 
	   	findK(a,i+1,high,k1,k2);
	   }else cout<<"概率分布有误"<<endl; 
	}
}

int main()
{  
  
   int a[] = {2,1,6,9,3};
   int len = sizeof(a)/sizeof(a[0]);
   double b[] = {0.2,0.2,0.1,0.4,0.1};
   for (int i=0;i<len;i++){
   	 p[a[i]] = b[i];    
   }
    findK(a,0,len-1,0,0);
    cout<<"-----------------"<<endl;
    
    
    int c[] = {2,1,3,6,9};
    double d[] = {0.2,0.1,0.1,0.4,0.2};
    int lenl = sizeof(c)/sizeof(c[0]);
    for(int j=0;j<lenl;j++){
    	p[c[j]] = d[j];
	}
	findK(c,0,lenl-1,0,0);
}

执行结果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值