找回密码
 欢迎注册
楼主: kon3155

[分享] 经典算法普及——基础篇

[复制链接]
 楼主| 发表于 2009-2-25 12:49:54 | 显示全部楼层
已知字母A,B和一组字母变换规则(至多100个规则): A1->B1 A2->B2 规则的含义为:如果A=Ak,可以通过一次变换为Bk(1≤k ≤ 规则数) 求从A到B最少需要几次变换。 【输入文件】letter.in 第一行为两个字母,分别是初始字母和变换目标字母。 以下k行为变换规则(1 ≤ k ≤ 100),都是大写字母,两个字母间以空格间隔,直到文件结束。 【输出文件】letter.out 最小的变换次数。如果无法变换,则输入”No Answer!” 【样例数据】 【输入】letter.in A Z A E E F F T T Z A C C Z 【输出】letter.out 2 【参考程序查看
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 12:50:40 | 显示全部楼层
在一个地图上有n(n≤20)个地窖,每个地窖中埋有一定数量的地雷,给出地窖之间的联系路径。当地窖极其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),挖雷的过程中允许某人重复经过地窖。当无连接时,挖地雷工作结束。请编程设计一个挖地雷的方案,使某人能挖到的最多的地雷。 【输入文件】miner.in n(地窖个数) v1 v2 v3 ... vn (每个地窖的地雷数) a(1,2) ... a(1,n) a(2,3) ... a(2,n) . . . a(n-1,n) (表示地窖之间连接路径,其中a(i,j)表示地窖i,j之间是否有通路,若有通路,则a(i,j)=1,若无通路,则a(i,j)=0) 【输出文件】miner.out R1-R2-...-Rk(挖地雷的顺序) Max(挖的地雷总数) 【样例数据】 【输入】miner.in 6 2 10 20 8 5 7 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 【输出】miner.out 2-3 30 【参考程序查看
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 12:51:24 | 显示全部楼层
乌托邦有n个城市,某些城市之间有公路连接。任意两个城市都可以通过公路直接或间接到达,并且任意两个城市之间有且仅有一条路径。 每条公路都有自己的长度,这些长度都是已经测量好的。小修想从一个城市出发开车到另一个城市,并且她希望经过的公路总长度最长。请问她应该选择哪两个城市?这个最长的长度是多少? 【输入文件】wutuo.in 第一行一个整数n(表示n个城市,n≤100),以下n-1行每行三个整数a,b,c。表示城市之间有公路连接,并且公路的长度是c(c≤10000)。 【输出文件】wutuo.out 仅一个数,即最长长度 【样例数据】 【输入】wutuo.in 5 1 2 2 2 3 1 2 4 3 1 5 4 【输出】wutuo.out 9 【参考程序查看
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 12:52:03 | 显示全部楼层
住在乌托邦首都(编号为1)的天凯,开始对首都的交通情况感到不满,因为,他发现首都到某些城市,即使他选择最短的路径,距离也非常远。因此他想让你求一下交通中心城市是哪座城市(也有可能就是首都)。 为了说明交通中心城市的概念,先定义G[j]为距离城市i最远的城市(到城市i的最短路径长度最长的城市)到城市i的距离。那么交通中心城市都是G[j]最小的城市,如果有几个城市的G[j]一样小,则是编号最小的那个。 【输入文件】capital.in 第一行两个整数n,m(n≤100)。下面m行,每行三个整数,第i+1行的整数表示第i条高速公路连接的两个城市编号和长度(0参考程序查看】 [ 本帖最后由 kon3155 于 2009-2-25 12:53 编辑 ]
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 12:54:14 | 显示全部楼层
【最短路径问题】 下图给出了一张地图,地图中每个顶点代表一个城市,两个城市间的连线代表道路,连线上的数值代表道路长度,求从A地到E地的最短路径。 【分析】本题可以利用深度搜索法求解,伪代码如下: var s:未访问的城市集合; dist[i,j]:存储任意两个城市间的距离数组; {0表示不连通}
  1. function search(city):integer; {求城市city到城市E的最短距离}
  2. begin
  3. if city=E then search←0;
  4. else begin
  5. min:=maxint;
  6. for i取遍所有城市 do
  7. if dist[city,i]>0 and (i∈s)
  8. then begin
  9. s←s-[i];
  10. j←dist[city,i]+search(i); {递归调用搜索过程}
  11. s←s+[i];
  12. if j<min then min←j;
  13. end;
  14. search←min;
  15. end;
  16. begin
  17. s←除E外所有城市;
  18. dist[A,E]←search(A);
  19. end.
复制代码
【效率评价】采用深度搜索的时间复杂度是W(n!),效率很低。主要的原因就在于重复计算了很多路径值。如果把每次计算得到的最短距离保存下来就可以节省很多时间,于是产生了动态规划的思路。 【动态规划】从城市A出发,按照与城市A的路径长度划分阶段。 阶段0包含的出发城市有{A} 阶段1包含的城市有{B1,B2} 阶段2包含的城市有{C1,C2,C3,D,C4} 阶段3包含的城市有{D1,D2,D3} 阶段4包含的城市有{E} 这种划分的性质如下: (1)阶段 i 的取值只与阶段 i+1 有关,阶段 i+1 的取值对阶段 i 的取值产生影响; (2)每个阶段的顺序是确定的,不可以调换任两个阶段的顺序。 从阶段4的城市E出发,按照阶段的顺序倒推至阶段0的城市A,得到如下算法:
  1. map[i,j]←两个城市之间的距离数组
  2. dist[E]←0;
  3. for k←3 downto 0 do
  4. for x 取遍k阶段的所有城市 do
  5. begin
  6. dist[x]←∞;
  7. for y取遍k+1阶段的所有城市 do
  8. if dist[y]+map[x,y]<dist[x]
  9. then dist[x]←dist[y]+map[x,y];
  10. end;
  11. 输出dist[A];
复制代码
[ 本帖最后由 kon3155 于 2009-2-25 12:56 编辑 ]
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 12:57:15 | 显示全部楼层
一、动态规划程序设计的基本概念 1、阶段k 将所给问题的过程,按时间或空间特征分解成若干相互联系的阶段,以便按次序去求每个阶段的解。设阶段变量为k。 2、状态Sk 各阶段开始的客观条件叫做状态,常用Sk表示各阶段的状态变量,Sk是k阶段的状态集合。 每个阶段的状态都是由以前阶段的状态以某种方式“变化”而来,这种“变化”称为状态转移。 将各阶段按照一定的次序排列好之后,对于阶段i的状态只能由阶段i+1的状态通过状态转移方程得来,与其他状态没有关系,尤其是未发生的状态没有关系。换句话说,每个状态都是“过去历史的一个完整总结”。就个特性称为“无后效性”。 3、决策 当各阶段的状态取定以后,就可以作出不同的决定,从而确定下一个阶段的状态,这种决定称为决策。表示决策的变量称为决策变量,常用Uk(Sk)表示第k阶段当状态为Sk时的决策变量,某个状态的决策可能有多个,以Dk(Sk)表示决策集合。 决策是问题解的属性。决策的目的就是“确定下一个阶段的状态”。 4、最优策略 在某一阶段的所有策略中,如有一个策略最优对于当前问题最优,则称最优策略。无论先前初始状态及初始策略如何,对于先前决策所形成的状态而言,其以后的所有决策应构成最优策略。这就是最优化原理。 5、最优指标函数 用于衡量所选定策略优劣的数量指标称为指标函数,最优指标函数记为Fk(Sk)。最优指标函数其实就是我们真正关心的问题的解。 二、动态规划程序设计的一般步骤 1、确定问题的研究对象,即状态。对于一个动态规划程序设计来说,状态的设计与存储比阶段的划分更重要,因为阶段只是一些可以等同处理的状态的集合,状态的选定对整个问题的处理起了决定性的作用。选定状态必须满足如下两点: ① 状态必须完全描述出事物的性质,两个不同的事物的状态是不同的。 ② 必须存在状态与状态之间的“转移方程”,以便可以由初始状态逐渐转化为目标状态。 2、划分阶段,确定阶段之间的状态转移方程。 3、考察此问题可否用动态规划程序设计方法解决,即问题是否具备最优子结构和无后效性的特征 4、如果发现问题目前不能用动态规划程序设计方法解决,则调整阶段的划分和状态的定义,使其具备最优子结构和无后效性的特征。 三、程序设计一般格式: Fn(Sn)←某个初始值; for k←n-1 downto 1 do for S 取遍所有状态 do for U 取遍所有决策 do Fk(Sk)取最优决策 ;
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 12:57:57 | 显示全部楼层
【骑士游历问题】 设有一个m×n的棋盘(2≤m≤50,2≤n≤50),在棋盘上任一点有一个中国象棋“马”,马走的规则为:马走日字;马只能向右走。当m,n给出后,同时给出马起始的位置和终点的位置,试找出从起点到终点所有路径的数目。 输入: m,n,x1,y1,x2,y2 (分别表示m,n、起点坐标和终点坐标) 输出: 路径数目(若不存在,则输出0) 【分析】 本题可以使用深度搜索发求解,但是效率很低,当路径很多时,不可能在短时间内出解。可以采用动态规划的设计思想。 从(x1,y1)位置出发,按照由左到右的顺序定义阶段的方向。位于(x2,y2)的左方且可达(x2,y2)的跳马位置集合都是(x2,y2)的子问题,起点至(x2,y2)的路径数实际上等于起点至这些位置集的路径数之和。可以按照阶段的顺序依次计算每一个阶段每个点的路径数目。 阶段i:中国象棋马当前的列位置(x1≤i≤x2) 状态j:中国象棋马在i列的行位置(1≤i≤m) 状态转移方程map[i,j]:起点(x1,y1)至(i,j)的路径数目 具体算法如下: fillchar(map,sizeof(map),0); map[x1,y1]←1; for i←x1+1 to x2 do for j←1 to m do map[i,j]←map[i-1,j-2]+map[i-1,j+2]+map[i-2,j-1]+map[i-2,j+1]; writeln(map[x2,y2]); 【参考程序
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 12:58:57 | 显示全部楼层
【最长递增子序列】 给定数列A1,A2,...An,求最长递增子序列 输入: 第一行一个整数n,表示有n个数(n<=1000) 第二行n个整数,用空格隔开。 输出: 最长递增子序列长度。 【分析】 在求以Ai为末元素的最长递增子序列时,找到所有序号在Ai前面且小于Ai的元素Aj,即j
  1. S[1]:=1; {以第一个元素为末元素的递增序列长度肯定是1}
  2. For i←2 to n do
  3. For j←1 to i-1 do
  4. Begin
  5. 搜索A[i]前面比A[i]小的数A[j],得到对应的S[j];
  6. S[i]←max{S[j]}+1;
  7. End;
  8. Write(max{S[i]});
复制代码参考程序】 [ 本帖最后由 kon3155 于 2009-2-25 14:26 编辑 ]
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 13:00:43 | 显示全部楼层
【合唱队形】 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<...Ti+1>…>TK(1<=i<=K)。 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。 【输入文件】 输入文件chorus.in的第一行是一个整数N(2<=N<=100),表示同学的总数。第二行有n个整数,用空格分隔,第i个整数Ti(130<=Ti<=230)是第i位同学的身高(厘米)。 【输出文件】 输出文件chorus.out包括一行,这一行只包含一个整数,就是最少需要几位同学出列。 【样例输入】 8 186 186 150 200 160 130 197 220 【样例输出】 4 【数据规模】 对于50%的数据,保证有n<=20; 对于全部的数据,保证有n<=100。 【分析】 假设第i位同学为最高个,则对其左边序列求最长递增序列长度,对其右边序列求最长递减序列长度,然后两者相加再减1(因为第i位同学被重复计算了一次)即可得到整个合唱队形的长度。可以利用两次动态规划求解,时间效率为O(N2) 依次枚举每一位同学为最高个,则N次之枚举后得到N个合唱队形长度,取其中最大值,然后(N-合唱队形最大值)即所求。 这样总的时间效率为O(N3)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-2-25 13:01:32 | 显示全部楼层
【石子合并】 在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。 试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。 【输入文件】 包含两行,第1 行是正整数n(1<=n<=100),表示有n堆石子。 第2行有n个数,分别表示每堆石子的个数。 【输出文件】 输出两行。 第1 行中的数是最小得分;第2 行中的数是最大得分。 【输入样例】 4 4 4 5 9 【输出样例】 43 54 【分析】 本题初看以为可以使用贪心法解决问题,但是事实上因为有必须相邻两堆才能合并这个条件在,用贪心法就无法保证每次都能取到所有堆中石子数最多的两堆。例如下面这个例子: 6 3 4 6 5 4 2 如果使用贪心法求最小得分,应该是如下的合并步骤: 第一次合并 3 4 6 5 4 2 2,3合并得分是5 第二次合并 5 4 6 5 4 5,4合并得分是9 第三次合并 9 6 5 4 5,4合并得分是9 第四次合并 9 6 9 9,6合并得分是15 第五次合并 15 9 15,9合并得分是24 总得分=5+9+9+15+24=62 但是如果采用如下合并方法,却可以得到比上面得分更少的方法: 第一次合并 3 4 6 5 4 2 3,4合并得分是7 第二次合并 7 6 5 4 2 7,6合并得分是13 第三次合并 13 5 4 2 4,2合并得分是6 第四次合并 13 5 6 5,6合并得分是11 第五次合并 13 11 13,11合并得分是24 总得分=7+13+6+11+24=61 由此我们知道本题是不可以使用贪心法求解的,上例中第五次合并石子数分别为13和11的相邻两堆。 这两堆石头分别由最初 的第1,2,3堆(石头数分别为3,4,6)和第4,5,6堆(石头数分别为5,4,2)经4次合并后形成的。于是问题又归结为如何使得这两个子序列的N-2次合并的得分总和最优。为了实现这一目标,我们将第1个序列又一分为二:第1、2堆构成子序列1,第3堆为子序列2。第一次合并子序列1中的两堆,得分7;第二次再将之与子序列2的一堆合并,得分13。显然对于第1个子序列来说,这样的合并方案是最优的。同样,我们将第2个子序列也一分为二;第4堆为子序列1,第5,6堆构成子序列2。第三次合 并子序列2中的2堆,得分6;第四次再将之与子序列1中的一堆合并,得分13。显然对于第二个子序列来说,这样的合并方案也是最优的。由此得出一个结论──6堆石子经过这样的5次合并后,得分的总和最小。 动态规划思路: 阶段i:石子的每一次合并过程,先两两合并,再三三合并,...最后N堆合并 状态s:每一阶段中各个不同合并方法的石子合并总得分。 决策:把当前阶段的合并方法细分成前一阶段已计算出的方法,选择其中的最优方案 具体来说我们应该定义一个数组s[i,j]用来表示合并方法,i表示从编号为i的石头开始合并,j表示从i开始数j堆进行合并,s[i,j]为合并的最优得分。 对于上面的例子来说,初始阶段就是s[1,1],s[2,1],s[3,1],s[4,1],s[5,1],s[6,1],因为一开始还没有合并,所以这些值应该全部为0。 第二阶段:两两合并过程如下,其中sum(i,j)表示从i开始数j个数的和 s[1,2]=s[1,1]+s[2,1]+sum(1,2) s[2,2]=s[2,1]+s[3,1]+sum(2,2) s[3,2]=s[3,1]+s[4,1]+sum(3,2) s[4,2]=s[4,1]+s[5,1]+sum(4,2) s[5,2]=s[5,1]+s[6,1]+sum(5,2) s[6,2]=s[6,1]+s[1,1]+sum(6,2) 第三阶段:三三合并可以拆成两两合并,拆分方法有两种,前两个为一组或后两个为一组 s[1,3]=s[1,2]+s[3,1]+sum(1,3)或s[1,3]=s[1,1]+s[2,2]+sum(1,3),取其最优 s[2,3]=s[2,2]+s[4,1]+sum(2,3)或s[1,3]=s[2,1]+s[3,2]+sum(2,3),取其最优 . . . 第四阶段:四四合并的拆分方法用三种,同理求出三种分法的得分,取其最优即可。以后第五阶段、第六阶段依次类推,最后在第六阶段中找出最优答案即可。 由此得到算法框架如下: For j←2 to n do {枚举阶段,从两两合并开始计算} For i←1 to n do {计算当前阶段的n种不同状态的值} For k←1 to j-1 do {枚举不同的分段方法} begin If i+k>n then t←(i+k) mod n else t←i+k {最后一个连第一个的情况处理} s[i,j]←最优{s[i,k]+s[t,j-k]+sum[1,3]} {sum[i,j]表示从i开始数j个数的和} end; 【参考程序
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-23 17:28 , Processed in 0.024422 second(s), 14 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表