算法教程3
2008-04-05 19:32
246 查看
第二章 算法应用
一、穷举搜索法
穷举搜索法是穷举所有可能情形,并从中找出符合要求的解。
穷举所有可能情形,最直观的是联系循环的算法。
[例]找出n个自然数(1,2,3,…,n)中r个数的组合。例如,当n=5,r=3时,所有组合为:
5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1
total=10 {组合的总数}
[解]n个数中r的组合,其中每r 个数中,数不能相同。另外,任何两组组合的数,所包含的数也不应相同。例如,5、4、3与3、4、5。为此,约定前一个数应大于后一个数。
将上述两条不允许为条件,当r=3时,可用三重循环进行搜索。
[程序]
Program zuhe11;
const n=5;
var i,j,k,t:integer;
begin t:=0;
for i:=n downto 1 do
for j:=n downto 1 do
for k:=n downto 1 do
if (i<>j)and(i<>k)and(i>j)and(j>k) then
begin t:=t+1;writeln(i:3,j:3,k:3);end;
writeln(';total=';,t);
end.
或者
Program zuhe12;
const n=5;r=3;
var i,j,k,t:integer;
begin t:=0;
for i:=n downto r do
for j:=i-1 downto r-1 do
for k:=j-1 downto 1 do
begin t:=t+1;writeln(i:3,j:3,k:3);end;
writeln(';total=';,t);
end.
这两个程序,前者穷举了所有可能情形,从中选出符合条件的解,而后者比较简洁。但是这两个程序都有一个问题,当r变化时,循环重数改变,这就影响了这一问题的解,即没有一般性。
但是,很多情况下穷举搜索法还是常用的。
二、递归法
递归法也是常用的方法。
[例]仍以前节例题为例,找n个数的r个数的组合。要求:
输入:n,r=5 3
输出:5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1
total=10 {组合的总数}
[解]分析所提示的10组数。首先固定第一位数(如5),其后是在另4个数中再“组合”2个数。这就将“5个数中3个数的组合”推到了“4个数中2个数的组合”上去了。第一位数可以是n r(如5 3),n个数中r个数组合递推到n-1个数中r-1个数有组合,这是一个递归的算法。即:
Procedure comb(n,r:integer);
var i:integer;
begin for i:=n downto r do
begin {固定i的输出位置}
comb(i-1,r-1); {原过程递推到i-1个数的r-1个数组合}
end;
end;
再考虑打印输出格式。
[程序]
Program zuhe2;
var k,n,r:integer;
Produrce comb(n,r:integer);
var i,temp:integer;
begin for i:=n downto r do
if (i<>n)and(k<>r) then {k为过程外定义的}
begin for temp:=1 to (k-r)*3 do write('; ';); {确定i的输出位置}
end;
write(i:3);
if i>1 then comb(i-1,r-1); {递推到下一情形}
else writeln;
end;
Begin {main}
write(';n,r=';);readln(n,r);
if r>n then
begin writeln(';Input n,r error!';);halt; end;
comb(n,r); {调用递归过程}
End;
三、回溯法
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
[例]再以前例说明,找n个数中r个数的组合。
[解]将自然数排列在数组A中:
A[1] A[2] A[3]
5 4 3
5 4 2
…
3 2 1
排数时从A[1] A[2] A[3],后一个至少比前一个数小1,并且应满足ri+A[ri]>r。若ri+A[ri]≤r就要回溯,该关系就是回溯条件。为直观起见,当输出一组组合数后,若最后一位为1,也应作一次回溯(若不回,便由上述回溯条件处理)。
[程序]
program zuhe3;
type tp=array[1..100] of integer;
var n,r:integer;
procedure comb2(n,r:integer;a:tp);
var i,ri:integer;
begin ri:=1;a[1]:=n;
repeat
if ri<>r then {没有搜索到底}
if ri+a[ri]>r then {是否回溯}
begin a[ri+1]:=a[ri]-1;
ri:=ri+1;
end
else
begin ri:=ri-1; a[ri]:=a[ri]-1;end; {回溯}
else
begin for j:=1 to r do write(a[j]:3);writeln; {输出组合数}
if a[r]=1 then {是否回溯}
begin ri:=ri-1; a[ri]:=a[ri]-1;end; {回溯}
else a[ri]:=a[ri]-1; {递推到下一个数}
end;
until a[1]<>r-1;
end;
begin {MAIN}
write(';n,r=';);readln(n,r);
if r>n then
begin writeln(';Input n,r error!';);halt; end
comb2(n,r);
end.
一、穷举搜索法
穷举搜索法是穷举所有可能情形,并从中找出符合要求的解。
穷举所有可能情形,最直观的是联系循环的算法。
[例]找出n个自然数(1,2,3,…,n)中r个数的组合。例如,当n=5,r=3时,所有组合为:
5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1
total=10 {组合的总数}
[解]n个数中r的组合,其中每r 个数中,数不能相同。另外,任何两组组合的数,所包含的数也不应相同。例如,5、4、3与3、4、5。为此,约定前一个数应大于后一个数。
将上述两条不允许为条件,当r=3时,可用三重循环进行搜索。
[程序]
Program zuhe11;
const n=5;
var i,j,k,t:integer;
begin t:=0;
for i:=n downto 1 do
for j:=n downto 1 do
for k:=n downto 1 do
if (i<>j)and(i<>k)and(i>j)and(j>k) then
begin t:=t+1;writeln(i:3,j:3,k:3);end;
writeln(';total=';,t);
end.
或者
Program zuhe12;
const n=5;r=3;
var i,j,k,t:integer;
begin t:=0;
for i:=n downto r do
for j:=i-1 downto r-1 do
for k:=j-1 downto 1 do
begin t:=t+1;writeln(i:3,j:3,k:3);end;
writeln(';total=';,t);
end.
这两个程序,前者穷举了所有可能情形,从中选出符合条件的解,而后者比较简洁。但是这两个程序都有一个问题,当r变化时,循环重数改变,这就影响了这一问题的解,即没有一般性。
但是,很多情况下穷举搜索法还是常用的。
二、递归法
递归法也是常用的方法。
[例]仍以前节例题为例,找n个数的r个数的组合。要求:
输入:n,r=5 3
输出:5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1
total=10 {组合的总数}
[解]分析所提示的10组数。首先固定第一位数(如5),其后是在另4个数中再“组合”2个数。这就将“5个数中3个数的组合”推到了“4个数中2个数的组合”上去了。第一位数可以是n r(如5 3),n个数中r个数组合递推到n-1个数中r-1个数有组合,这是一个递归的算法。即:
Procedure comb(n,r:integer);
var i:integer;
begin for i:=n downto r do
begin {固定i的输出位置}
comb(i-1,r-1); {原过程递推到i-1个数的r-1个数组合}
end;
end;
再考虑打印输出格式。
[程序]
Program zuhe2;
var k,n,r:integer;
Produrce comb(n,r:integer);
var i,temp:integer;
begin for i:=n downto r do
if (i<>n)and(k<>r) then {k为过程外定义的}
begin for temp:=1 to (k-r)*3 do write('; ';); {确定i的输出位置}
end;
write(i:3);
if i>1 then comb(i-1,r-1); {递推到下一情形}
else writeln;
end;
Begin {main}
write(';n,r=';);readln(n,r);
if r>n then
begin writeln(';Input n,r error!';);halt; end;
comb(n,r); {调用递归过程}
End;
三、回溯法
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
[例]再以前例说明,找n个数中r个数的组合。
[解]将自然数排列在数组A中:
A[1] A[2] A[3]
5 4 3
5 4 2
…
3 2 1
排数时从A[1] A[2] A[3],后一个至少比前一个数小1,并且应满足ri+A[ri]>r。若ri+A[ri]≤r就要回溯,该关系就是回溯条件。为直观起见,当输出一组组合数后,若最后一位为1,也应作一次回溯(若不回,便由上述回溯条件处理)。
[程序]
program zuhe3;
type tp=array[1..100] of integer;
var n,r:integer;
procedure comb2(n,r:integer;a:tp);
var i,ri:integer;
begin ri:=1;a[1]:=n;
repeat
if ri<>r then {没有搜索到底}
if ri+a[ri]>r then {是否回溯}
begin a[ri+1]:=a[ri]-1;
ri:=ri+1;
end
else
begin ri:=ri-1; a[ri]:=a[ri]-1;end; {回溯}
else
begin for j:=1 to r do write(a[j]:3);writeln; {输出组合数}
if a[r]=1 then {是否回溯}
begin ri:=ri-1; a[ri]:=a[ri]-1;end; {回溯}
else a[ri]:=a[ri]-1; {递推到下一个数}
end;
until a[1]<>r-1;
end;
begin {MAIN}
write(';n,r=';);readln(n,r);
if r>n then
begin writeln(';Input n,r error!';);halt; end
comb2(n,r);
end.
相关文章推荐
- 在Python中实现贪婪排名算法的教程
- Cocos2d-x教程(34)-三维物体OBB碰撞检测算法
- Java集合框架官方教程(6):算法
- 【★】SPF(Dijkstra)算法完美教程
- 算法教程(1)zz
- 旧金山大学的算法可视化学习教程 赞的教程,将抽象的算法可视化,易于理解
- opencv3.3中基于ssd算法的目标检测示例教程
- 基于大数据技术推荐系统算法案例实战教程
- VTK教程之十&nbsp;可视化基础算法-三维…
- JavaScript算法教程之sku(库存量单位)详解
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(七)传说中的A*寻径算法
- 关于数据结构教程P67例3.4的算法的一点优化
- A Painless Q-learning Tutorial (一个 Q-learning 算法的简明教程)
- 机器学习教程 之 集成学习算法: 深入刨析AdaBoost
- [转]【OpenCV入门教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)
- Swift开发教程--火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法
- A Painless Q-learning Tutorial (一个 Q-learning 算法的简明教程)
- I学霸官方免费教程二十八:Java排序算法之选择排序和冒泡排序
- [黑金原创教程] FPGA那些事儿《数学篇》- CORDIC 算法
- A Painless Q-learning Tutorial (一个 Q-learning 算法的简明教程)