初识分治法,动态规划——中位数,Gray码与零钱问题

通过学习算法设计与分析课程,我想对于那些经典的算法,除了在理论上认识他们外,最主要是在思想上学会他们,接受他们,这样不知不觉地培养了我们一种严密的思维能力,并且运用所学知识结合具体问题设计适用的算法的能力。而且那些经典算法也有很多复杂的应用领域,但是对于没有涉足这方面的人来说,由认识他们再上升到算法思想上的掌握也是很有必要的。

下面介绍的几个应用例子都是相对来说不是很难的,主要是先有一种感性的认识。
  • 有关分治法思想
分而治之方法与软件设计的模块化方法非常相似。为了解决一个大的问题,可以: 1) 把它分成两个或多个更小的问题;
2) 分别解决每个小问题;
3) 把各小问题的解答组合起来,即可得到原问题的解答。
小问题通常与原问题相似,可以递归地使用分而治之策略来解决。
中位数问题
问题的提出
对于两个长度均为n的已排序的序列,确定这两个序列的2n个元素的中位数
解决此问题的算法思想
设两个长度为n的数列分别为x[ 0 : n -1]y[ 0 : n -1],分别找出这两个数列的中位数x[i]
y[ j ],二者进行比较,根据比较结果可以在每个数列中减少一半的搜索范围,然后再分别取
两个子数列的中位数再比较,再减少搜索范围,继续下去直到找到最后结果
求解过程
查找范围确定:
  • n为奇数时,令n=2m +1,则两个数列的中位数分别为x[ m ] y[ m ],则:
    x[0:m-1]<x[m]<x[m+1:2m]

    y[0:m-1]<y[m]<y[m+1:2m]
    x[m]<y[m]
    若整体中位数x[k]x[0:m-1]中,则
    x[k]<x[m]<x[m+1:2m] x[k]<y[m]<y[m+1:2m]
    x[k]至少小于2m+2n+1个数,而整体的中位数应该是第n个数,它小于n个数,所以整体中位数不在x的前半部分,同样不会在y的后半部分。
     x[m]至少小于n个数,y[m]至少大于n个数,所以这两个局部中位数都有可能成为整体中位数.    
     所以再次查找范围为x[m:2m]y[0:m]
  • n为偶数时,令n=2m ,则两个数列的中位数分别为x[ m-1 ] y[ m-1 ],则:
    x[0:m-2]<x[m-1]<x[m:2m-1]

    y[0:m-2]<y[m-1]<y[m:2m-1]
    x[m-1]<y[m-1]
    若整体中位数x[k]x[0:m-2]中,则
    x[k]<x[m-1]<x[m:2m-1] x[k]<y[m-1]<y[m:2m-1]
    x[k]至少小于2m+1即n+1个数,而整体的中位数应该是n个数,它小于n个数,所以整体中位数不在x的前半部分,同样不会在y的后半部分。
     x[m-1]至少小于n+1个数,所以其不会成为整体中位数,y[m-1]至少大于n-1个数,所以它有可能成为整体中位数
     所以再次查找范围为x[m:2m-1]y[0:m-2]
举个例子:
x={10, 15, 16, 19, 24}
y={11, 17, 18, 20, 23}
x1={16, 19, 24} y1= {11, 17, 18 }
x2={16,19} y2={17,18}
x2={19} y2={17} ————
出口,应单独处理
x={10, 15, 16, 19}
y={11, 17, 18, 20}
x1={16, 19} y1= {11, 17}
x2={16} y2={17}
mid=16
数据输入
由文件input.txt提供输入数据。文件的第1行中有1个正整数nn<=200),表示每个数组有n个数。接下来的两行分别是XY数组的元素。
输入文件示例
输出文件示例
input.txt
output.txt
3
5 15 18
3 14 21
14
C++实现:
初识分治法,动态规划——中位数,Gray码与零钱问题#include<iostream>
初识分治法,动态规划——中位数,Gray码与零钱问题#include<fstream>
初识分治法,动态规划——中位数,Gray码与零钱问题
usingnamespacestd;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intfindMedian(int*,int*,int);
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intmain()
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题ifstream
in("in.txt");
初识分治法,动态规划——中位数,Gray码与零钱问题ofstream
out("d://out.txt");
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intn;
初识分治法,动态规划——中位数,Gray码与零钱问题
int*x,*y;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
in>>n;
初识分治法,动态规划——中位数,Gray码与零钱问题x=
newint[n];
初识分治法,动态规划——中位数,Gray码与零钱问题y=
newint[n];
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
for(inti=0;i<n;i++)
初识分治法,动态规划——中位数,Gray码与零钱问题
in>>x[i];
初识分治法,动态规划——中位数,Gray码与零钱问题
for(i=0;i<n;i++)
初识分治法,动态规划——中位数,Gray码与零钱问题
in>>y[i];
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intmedian=findMedian(x,y,n);
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题cout<<median<<endl;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
out<<median;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
in.close();
初识分治法,动态规划——中位数,Gray码与零钱问题
out.close();
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
return1;
初识分治法,动态规划——中位数,Gray码与零钱问题}
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intfindMedian(int*x,int*y,intn)
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题
if(n==1)
初识分治法,动态规划——中位数,Gray码与零钱问题
return*x<=*y?*x:*y;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intm=(n-1)/2;//
中位数位置
初识分治法,动态规划——中位数,Gray码与零钱问题
intp=m+1;//中位数小者子数字起始位置
初识分治法,动态规划——中位数,Gray码与零钱问题

初识分治法,动态规划——中位数,Gray码与零钱问题
if(n%2!=0)//n为奇数
初识分治法,动态规划——中位数,Gray码与零钱问题
p--;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
if(*(x+m)==*(y+m))
初识分治法,动态规划——中位数,Gray码与零钱问题
return*(x+m);
初识分治法,动态规划——中位数,Gray码与零钱问题
elseif(*(x+m)(y+<*m))
初识分治法,动态规划——中位数,Gray码与零钱问题
returnfindMedian(x+p,y,m+1);
初识分治法,动态规划——中位数,Gray码与零钱问题
else
初识分治法,动态规划——中位数,Gray码与零钱问题
returnfindMedian(x,y+p,m+1);
初识分治法,动态规划——中位数,Gray码与零钱问题}
Gray码问题
Gray码是一个长度为2n的序列。序列中无相同的元素,每个 元素长度都为n位的串,相邻元素恰好之有一位不同,对任意的n位如何构造相应的Gray码。
对于n=4的Gray码,如下图所。
初识分治法,动态规划——中位数,Gray码与零钱问题
上图 第1列从最左边算起
实现这个问题的方法是,递归上半部分,下半部分对称复制上半分部即可
由文件input.txt提供输入数据n。
用C++ 实现:
初识分治法,动态规划——中位数,Gray码与零钱问题#include<iostream>
初识分治法,动态规划——中位数,Gray码与零钱问题#include
<fstream>
初识分治法,动态规划——中位数,Gray码与零钱问题#include
<stdio.h>
初识分治法,动态规划——中位数,Gray码与零钱问题#include
<math.h>
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
usingnamespacestd;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
voidGraycode(inta,intb,int**arr)
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题
//递归出口
初识分治法,动态规划——中位数,Gray码与零钱问题
if(a==1)
初识分治法,动态规划——中位数,Gray码与零钱问题
return;
初识分治法,动态规划——中位数,Gray码与零钱问题
//处理当前列
初识分治法,动态规划——中位数,Gray码与零钱问题
for(inti=0;i<a/2;i++)
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题arr[i][b
-1]=0;//上半部分赋值为0
初识分治法,动态规划——中位数,Gray码与零钱问题
arr[a-i-1][b-1]=1;//下半部分赋值为1
初识分治法,动态规划——中位数,Gray码与零钱问题
}

初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
//处理子问题
初识分治法,动态规划——中位数,Gray码与零钱问题
Graycode(a/2,b-1,arr);//递归调用子问题,生成列数为b-1的Gray码,填写高半部分
初识分治法,动态规划——中位数,Gray码与零钱问题

初识分治法,动态规划——中位数,Gray码与零钱问题
for(intk=a/2;k<a;k++)//将(n-1)位的Gray码逆序后,填入目标码字/的低半部分
初识分治法,动态规划——中位数,Gray码与零钱问题
for(intj=0;j<b-1;j++)
初识分治法,动态规划——中位数,Gray码与零钱问题arr[k][j]
=arr[a-k-1][j];
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题}

初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intmain()
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intn;
初识分治法,动态规划——中位数,Gray码与零钱问题ifstream
in("in.txt");
初识分治法,动态规划——中位数,Gray码与零钱问题ofstream
out("d://out.txt");
初识分治法,动态规划——中位数,Gray码与零钱问题
in>>n;
初识分治法,动态规划——中位数,Gray码与零钱问题
introw=pow(2,n);
初识分治法,动态规划——中位数,Gray码与零钱问题
int**arr=newint*[row];
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
for(intm=0;m<row;m++)...{
初识分治法,动态规划——中位数,Gray码与零钱问题arr[m]
=newint[n];
初识分治法,动态规划——中位数,Gray码与零钱问题}

初识分治法,动态规划——中位数,Gray码与零钱问题Graycode(row,n,arr);
初识分治法,动态规划——中位数,Gray码与零钱问题
for(inti=0;i<row;i++)
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题
for(intj=0;j<n;j++)
初识分治法,动态规划——中位数,Gray码与零钱问题cout
<<arr[i][j];
初识分治法,动态规划——中位数,Gray码与零钱问题cout
<<endl;
初识分治法,动态规划——中位数,Gray码与零钱问题}

初识分治法,动态规划——中位数,Gray码与零钱问题
in.close();
初识分治法,动态规划——中位数,Gray码与零钱问题
out.close();
初识分治法,动态规划——中位数,Gray码与零钱问题
return1;
初识分治法,动态规划——中位数,Gray码与零钱问题}
  • 有关动态规划的思想
零钱问题

设有n种不同面值的硬币,各硬币的面值存于数组T[1:n]中。现要用这些面值的硬币来找钱,可以实用的各种面值的硬币个数不限。当只用硬币面值T[1],T[2],…,T[i]时,可找出钱数j的最少硬币个数记为C(i,j)。若只用这些硬币面值,找不出钱数j时,记C(i,j)=∞:<shapetype id="_x0000_t75" stroked="f" filled="f" path="[email protected]@[email protected]@[email protected]@[email protected]@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"></shapetype><shape id="_x0000_i1025" style="WIDTH: 415.5pt; HEIGHT: 231pt" type="#_x0000_t75"><imagedata src="file:///E:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C08%5Cclip_image001.jpg" o:title="666"></imagedata></shape>

初识分治法,动态规划——中位数,Gray码与零钱问题<stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><lock aspectratio="t" v:ext="edit"></lock>

« 数据输入

由文件input.txt提供输入数据。文件的第1行中有1个正整数nn<=13),表示有n种硬币可选。接下来的一行是每种硬币的面值。由用户输入待找钱数j

使用C++语言实现

初识分治法,动态规划——中位数,Gray码与零钱问题#include<fstream>
初识分治法,动态规划——中位数,Gray码与零钱问题#include
<iostream>
初识分治法,动态规划——中位数,Gray码与零钱问题#include
<algorithm>
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
usingnamespacestd;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intchangeCoins(int*T,intn,intv);
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intmain()
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题ifstream
in("in.txt");
初识分治法,动态规划——中位数,Gray码与零钱问题ofstream
out("d://out.txt");
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intn;
初识分治法,动态规划——中位数,Gray码与零钱问题
intv;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
in>>n;
初识分治法,动态规划——中位数,Gray码与零钱问题
int*T=newint[n];
初识分治法,动态规划——中位数,Gray码与零钱问题
for(inti=0;i<n;i++)
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题
in>>T[i];
初识分治法,动态规划——中位数,Gray码与零钱问题}

初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
in>>v;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intresult=changeCoins(T,n,v);
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题cout
<<result<<endl;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
out<<result;
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
in.close();
初识分治法,动态规划——中位数,Gray码与零钱问题
out.close();
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
return1;
初识分治法,动态规划——中位数,Gray码与零钱问题}

初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
初识分治法,动态规划——中位数,Gray码与零钱问题
intchangeCoins(int*T,intn,intv)
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
...{
初识分治法,动态规划——中位数,Gray码与零钱问题
//先对3个硬币按面值进行排序
初识分治法,动态规划——中位数,Gray码与零钱问题
sort(T,T+n);
初识分治法,动态规划——中位数,Gray码与零钱问题
int**c=newint*[n];
初识分治法,动态规划——中位数,Gray码与零钱问题初识分治法,动态规划——中位数,Gray码与零钱问题
for(intm=0;m<n;m++)...{
初识分治法,动态规划——中位数,Gray码与零钱问题c[m]
=newint[v+1];
初识分治法,动态规划——中位数,Gray码与零钱问题}

初识分治法,动态规划——中位数,Gray码与零钱问题
//初始化第一行,只有一个硬币时的情况
初识分治法,动态规划——中位数,Gray码与零钱问题
for(inti=0;i<=v;i++)
初识分治法,动态规划——中位数,Gray码与零钱问题
if(i%T[0]==0)
初识分治法,动态规划——中位数,Gray码与零钱问题c[
0][i]=i/T[0];
初识分治法,动态规划——中位数,Gray码与零钱问题
else
初识分治法,动态规划——中位数,Gray码与零钱问题c[
0][i]=INT_MAX;
初识分治法,动态规划——中位数,Gray码与零钱问题
//从第二行开始
初识分治法,动态规划——中位数,Gray码与零钱问题
for(intj=1;j<n;j++)
初识分治法,动态规划——中位数,Gray码与零钱问题
for(intk=0;k<=v;k++)
初识分治法,动态规划——中位数,Gray码与零钱问题
//新加进来的硬币大于要找的钱,用不到这个硬币,所以还是跟上一行的一样
初识分治法,动态规划——中位数,Gray码与零钱问题
if(k<T[j])
初识分治法,动态规划——中位数,Gray码与零钱问题c[j][k]
=c[j-1][k];
初识分治法,动态规划——中位数,Gray码与零钱问题
else
初识分治法,动态规划——中位数,Gray码与零钱问题c[j][k]
=