算法实验二题库二.docx
《算法实验二题库二.docx》由会员分享,可在线阅读,更多相关《算法实验二题库二.docx(30页珍藏版)》请在冰豆网上搜索。
![算法实验二题库二.docx](https://file1.bdocx.com/fileroot1/2022-11/29/fe42a87c-6b2f-477a-b210-284bc5aa23fc/fe42a87c-6b2f-477a-b210-284bc5aa23fc1.gif)
算法实验二题库二
南通大学
算法设计与分析
实验报告
姓名:
鹿瑶
班级:
软件工程122
学号:
1213042037
日期:
2014.12.16
目录
Question-2编程实现循环赛日程表(分治法)……………………3
Question-3编程实现最长公共子序列(动态规划)………………3
Question-4TheTriangle(动态规划)………………………………4
Question-5超级台阶(动态规划)…………………………………5
Question-6最大和(动态规划)……………………………………6
Question-7剑客决斗(动态规划)…………………………………7
Question-8最长上升子序列问题(动态规划)……………………8
Question-9独木舟上的旅行(贪婪法)……………………………9
Question-10背包问题(贪心算法)………………………………10
Question-11田忌赛马(动规中的贪心算法)……………………10
Question-12硬币问题(贪心算法)………………………………11
附:
源代码……………………………………………………………12
Question-2编程实现循环赛日程表(分治法)
描述
设有n=2k个运动员要进行网球循环赛,先要设计一个满足一下要求的比赛日常表:
(1)每个选手必须与其他n-1个选手各赛一次
(2)每个选手一天只能赛一次
(3)循环赛一共进行n-1天
算法设计
将n*n个格子,也就是n阶方阵从中间十字划分,一次划分分成四块,令其右上角和左下角的数据完全相同,右下角和左上角的数据完全相同;每次划分都得到了若干个n/2阶的方阵,然后对这些方阵进行操作,继续令其右上角和左下角的数据完全相同,右下角和左上角的数据完全相同,如此循环下去,直至n<2时结束递归。
运行结果
Question-3编程实现最长公共子序列(动态规划)
描述
如题,需要你做的就是写一个程序,得出最长公共子序列。
tip:
最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(LongestCommon
Subsequence)。
其定义是,一个序列S,如果分别是两个或多个已知序列的子序列,且是
所有符合此条件序列中最长的,则S称为已知序列的最长公共子序列。
输入
第一行给出一个整数N(0接下来每组数据两行,分别为待测的两组字符串。
每个字符串长度不大于1000.
算法设计
由最长公共子序列问题的最优子结构性质可知,要找出X=和Y=的最长公共子序列,可按以下方式递归地进行:
当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。
当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。
这两个公共子序列中较长者即为X和Y的一个最长公共子序列。
由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。
例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列。
而这两个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最长公共子序列。
与矩阵连乘积最优计算次序问题类似,我们来建立子问题的最优值的递归关系。
用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。
其中Xi=,Yj=。
当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。
其他情况下,由定理可建立递归关系如下:
运行结果:
Question-4TheTriangle(动态规划)
描述
7
38
810
2744
45265
在上图所示的三角形中,从顶部到底部,找一条路线,使得它的和最大。
当然,每一步只能走左下或者右下。
算法分析
利用动态规划的基本步骤来分析,首先找出最优解结构,l[i]表示1到i层路径的最优解,则l[i-1]亦为最优解(证明:
如果l[i-1]不为最优解,则1到i-1层有另外一条路径使得l[i-1]为最优解,这样就会致使l[i]路径不为最优解,矛盾)。
最优解结构:
这里用一位数组存储数字三角形。
运行结果
Question-5超级台阶(动态规划)
描述
有一楼梯共m级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第m级,共
有多少走法?
注:
规定从一级到一级有0种走法。
输入
输入数据首先包含一个整数n(1<=n<=100),表示测试实例的个数,然后是n行数据,每行
包含一个整数m,(1<=m<=40),表示楼梯的级数。
输出
对于每个测试实例,请输出不同走法的数量。
(即有两个不同的楼梯,一个楼梯有2级,一个楼梯有3级)
算法设计
只能说这题有一点DP的思想。
。
简单递归
运行结果
Question-6最大和(动态规划)
描述
给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵。
例子:
0-2-70
92-62
-41-41
-180-2
其最大子矩阵为:
92
-41
-18
其元素总和为15。
输入
第一行输入一个整数n(0每组测试数据:
第一行有两个的整数r,c(0输出
输出矩阵的最大子矩阵的元素之和。
算法分析
用2维数组a[1:
m][1:
n]表示给定的m行n列的整数矩阵。
子数组a[i1 :
i2][j1 :
j2]表示左上角和右下角行列坐标分别为(i1,j1)和(i2,j2)的子矩阵,其各元素之和记为:
(1)
最大子矩阵和问题的最优解即为:
(2)
(3)
如果令:
(4)
那么式(4)就是我们熟悉的最大子序列和的问题。
根据以上分析我们可得到最大子矩阵和问题的算法:
运行结果
Question-7剑客决斗(动态规划)
描述
在路易十三和红衣主教黎塞留当权的时代,发生了一场决斗。
n个人站成一个圈,依次抽签。
抽中的人和他右边的人决斗,负者出圈。
这场决斗的最终结果关键取决于决斗的顺序。
现书籍任意两决斗中谁能胜出的信息,但“A赢了B”这种关系没有传递性。
例如,A比B强,B比C强,C比A强。
如果A和B先决斗,C最终会赢,但如果B和C决斗在先,则最后A会赢。
显然,他们三人中的第一场决斗直接影响最终结果。
假设现在n个人围成一个圈,按顺序编上编号1~n。
一共进行n-1场决斗。
第一场,其中一人(设i号)和他右边的人(即i+1号,若i=n,其右边人则为1号)。
负者被淘汰出圈外,由他旁边的人补上他的位置。
已知n个人之间的强弱关系(即任意两个人之间输赢关系)。
如果存在一种抽签方式使第k个人可能胜出,则我们说第k人有可能胜出,我们的任务是根据n个人的强弱关系,判断可能胜出的人数。
输入
第一行是一个整数N(1<=N<=20)表示测试数据的组数。
第二行是一个整数n表示决斗的总人数。
(2<=n<=500)
随后的n行是一个n行n列的矩阵,矩阵中的第i行第j列如果为1表示第i个人与第j个人决斗时第i个人会胜出,为0则表示第i个人与第j个人决斗时第i个人会失败。
输出
对于每组测试数据,输出可能胜出的人数,每组输出占一行。
算法设计
动态规划(弗洛伊德),可以把一圈人从x分为两端都是x的一条线,x向中间打若最终x能遇到x则说明x可以取得胜利,中间得到meet[i][j]的转移方程有点像弗洛伊德算法,从中间找可以作为媒介的点,然后更新meet数组。
因为是在圈里所以要注意%操作。
运行结果
Question-8最长上升子序列问题(动态规划)
描述
有一个长为n的数列a0,a1,„„,an-1。
请求出这个序列中最长的上升子序列的长度。
上升子
序列指的是对于任意的i(1≤n≤1000,0≤ai≤1000000)。
输入
第一行为n,下面一行为a0~an-1。
输出
最长上升子序列的长度。
算法设计
我们依次遍历整个序列,每一次求出从第一个数到当前这个数的最长上升子序列,直至遍历到最后一个数字为止,然后再取dp数组里最大的那个即为整个序列的最长上升子序列。
我们用dp[i]来存放序列1-i的最长上升子序列的长度,那么dp[i]=max(dp[j])+1,(j∈[1,i-1]);显然dp[1]=1,我们从i=2开始遍历后面的元素即可。
运行结果:
Question-9独木舟上的旅行(贪婪法)
描述
进行一次独木舟的旅行活动,独木舟可以在港口租到,并且之间没有区别。
一条独木舟最多
只能乘坐两个人,且乘客的总重量不能超过独木舟的最大承载量。
我们要尽量减少这次活动中的花销,所以要找出可以安置所有旅客的最少的独木舟条数。
现在请写一个程序,读入独木舟的最大承载量、旅客数目和每位旅客的重量。
根据给出的规则,计算要安置所有旅客必须的最少的独木舟条数,并输出结果。
输入
第一行输入s,表示测试数据的组数;
每组数据的第一行包括两个整数w,n,80<=w<=200,1<=n<=300,w为一条独木舟的最大承载量,n为人数;接下来的一组数据为每个人的重量(不能大于船的承载量)。
输出
每组人数所需要的最少独木舟的条数。
算法设计
先把各个人的体重排序,然后计算最重的人和最轻的人能否同乘一条舟,如果不能,则最重的人就要单独乘坐一条舟,再求最轻的和第二重的人的和,依次比较。
运行结果
Question-10背包问题(贪心算法)
描述
现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w<=10);如果给你一个背包它能容纳的重量为m(10<=m<=20),你所要做的就是把物品装到背包里,使背包里的物品的价值总和最大。
输入
第一行输入一个正整数n(1<=n<=5),表示有n组测试数据;随后有n测试数据,每组测试数据的第一行有两个正整数s,m(1<=s<=10);s表示有s个物品。
接下来的s行每行有两个正整数v,w。
输出
输出每组测试数据中背包内的物品的价值和,每次输出占一行。
算法设计
贪心原理,要求背包物品总价值最大,故尽可能多存放价值大的物品;如图题目中给出的例子,背包可容纳重量15,故先放价值最大的A,将10斤A全部放入背包,然后放入价值次大的C,此时背包容纳量剩下15-10=5,而C还有9斤,因此剩下的全放C,总价值=(10*5)+(5*3)=65。
运行结果
Question-11田忌赛马(动规中的贪心算法)
描述
田忌赛马的故事大家应该都听过吧。
田忌经常与齐国众公子赛马,设重金赌注。
孙膑发
现他们的马脚力都差不多,马可分为上、中、下三等。
于是孙膑对田忌说:
“您只管下
大赌注,我能让您取胜。
”田忌相信并答应了他,与齐王和诸公子用千金来赌注。
比赛
即将开始,孙膑说:
“现在用您的下等马对付他们的上等马,拿您的上等马对付他们的
中等马,拿您的中等马对付他们的下等马。
”已经比了三场比赛,田忌一场败而两场胜,
最终赢得齐王的千金赌注。
现在题目的要求是这样的,给出田忌n匹马的速度,再给出
公子n匹马的速度,运用上述思想,求田忌最多能赢几场比赛。
我们规定,赢一场可
得200两黄金,输一场就扣200量黄金。
平局不得也不扣。
求田忌最多能赢多少黄金。
输入
测试数据有多个。
每组测试数据的第一行是为n的正整数。
(1<=n<=1000),接下来的
两行为马的速度。
第一行为田忌的n匹马的速度,第二行为公子的n匹马的速度。
输出
对于每一个测试用例,每行输出一个数,该数为田忌所能赢的最多的黄金数。
算法设计
1如果田忌的慢马比齐王的慢马快,直接比赛。
赢的代价小!
2如果田忌的慢马比齐王的慢马慢,让他和齐王的快马比赛。
输的值!
3如果田忌的慢马的速度等于齐王的慢马1)如果田忌的快马比齐王的快马快,直接比赛。
赢!
2)如果田忌的慢马比齐王的快马慢,那让他和齐王最快的马比赛。
输的值!
3)其他情况,直接退出。
统计比赛结果,算钱!
运行结果
Question-12硬币问题(贪心算法)
描述
有1元、5元、10元、50元、100元、500元的硬币各C1、C5、C10、C50、C100、C500枚。
现在要用这些硬币来支付A元、最少需要多少枚硬币?
假定本题至少存在一种支付方案。
输入
第一行n为测试数据的组数。
以下各行依次为:
C1C5C10C50C100C500A
输出
每行输出需要最少的硬币数
算法设计
由贪心算法可知尽量用大面值的硬币组合来找钱,可以使使用的硬币最少。
而贪心算法对最少硬币问题的解决总是可以得到最优解很好的近似解。
本算法就是用贪心策略枚举出所有近似最优解,然后从中寻找到问题的最优解 寻找近似最优解群 。
(1)将硬币依面值大小排序
(2)按面值种类划分不同情况
有多少种面值就划分多少种情况. 每种情况的第一枚硬币面值各不一样,其后对剩余的硬币按面值从大到小排列。
运行结果
附:
源代码
Question-2
#include
usingnamespacestd;
#defineMAX100
//定义每组比赛成员的结构类型
typedefstructnode
{
intp1;
intp2;
}team;
teamX[MAX][MAX/2+1];//X为解向量x[i][j]表示第i天第j场次现在赛的情况x[i][j].p1和x[i][j].p2
intnum,t[MAX];//num表示比赛人数t[]分别表示每天比赛的场次数初始化为0
voidInit()
{
cout<<"请输入运动员人数:
";
cin>>num;
for(inti=0;i}
voidf(intfrom,intto,intday)//编号为from到to的n(n=to-from+1)个人从第day天开始比赛,全部安排下去的函数
{
intn=to-from+1,i,k;
if(n<2)return;
if(n==2)//只有两人,直接在第day天安排比赛,比赛场次为++t[day]
{
X[day][++t[day]].p1=from;
X[day][t[day]].p2=to;
}
if(n>2)//超过两人,才分成两组
{
intmid=from+n/2-1;
f(from,mid,day);//组内比赛
f(mid+1,to,day);//组内比赛
//以下是组间比赛
for(k=0;k<=n/2;k++)//在后n/2天内,分别与组2内队员(j+i+k)%(n/2)进行组间比赛
for(i=0;i<=n/2;i++)
{
X[n/2+k][++t[n/2+k]].p1=from+i;
X[n/2+k][t[n/2+k]].p2=(i+k)%(n/2+1)+mid+1;
}
}
}
voidOutput()
{
cout<<"比赛安排如下:
\n";
for(inti=1;i<=num;i++)
{
cout<<"第"<
"<for(intj=1;j<=t[i];j++)
{
cout<'<<'('<}
cout<}
}
intmain()
{
intz;
Init();//初始化
f(1,num,1);//从1到num个人从第一天开始调用函数
Output();
cout<<"输入任意字符结束...";
cin>>z;
return0;
}
Question-3
#include
#include
#defineN100
usingnamespacestd;
inta[N][N];
chars1[N],s2[N];
intmax(inta,intb)
{
returna>=b?
a:
b;
}
intmain()
{
intcount,i,j,length1,length2,z;
cout<<"请输入需要测试几组数据:
";
cin>>count;
while(count--)
{
intcount=1;
cout<<"请输入第"<"<cin>>s1+1>>s2+1;
length1=strlen(s1+1);
length2=strlen(s2+1);
for(i=0;i<=length1;i++)
{
a[i][0]=0;
}
for(i=0;i<=length2;i++)
{
a[0][i]=0;
}
for(i=1;i<=length1;i++)
{
for(j=1;j<=length2;j++)
{
if(s1[i]==s2[j])
{
a[i][j]=a[i-1][j-1]+1;
}
elsea[i][j]=max(a[i-1][j],a[i][j-1]);
}
}
cout<<"最长公共子序列长度为:
"<count++;
}
cout<<"输入任意字符结束...";
cin>>z;
return0;
}
Question-4
#include
#defineN105
usingnamespacestd;
inta[N][N],dp[N][N],z;
intmain(){
intn,i,j,min;
cout<<"输入行数:
";
while(cin>>n){
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
{
cin>>a[i][j];
dp[i][j]=0;
}
dp[1][1]=a[1][1];
for(i=2;i<=n;i++){
dp[i][1]=a[i][1]+dp[i-1][1];
for(j=2;j<=i;j++){
min=dp[i-1][j-1]>dp[i-1][j]?
dp[i-1][j-1]:
dp[i-1][j];
dp[i][j]=a[i][j]+min;
}
}
intans=0;
for(i=1;i<=n;i++)
if(ansans=dp[n][i];
cout<<"自上而下路径最大和为:
"<}
cout<<"输入任意字符结束...";
cin>>z;
return0;
}
Question-5
#include
usingnamespacestd;
intmain()
{
intN;
cout<<"请输入测试实例个数:
";
cin>>N;
__int64array[1024];
memset(array,0,1024);
cout<<"请输入每个实例的楼梯级数:
";
while(N--)
{
intsum=0;
cin>>sum;
array[2]=1;
array[1]=1;
for(intindex=3;index<=sum;index++)
{
array[index]=array[index-1]+array[index-2];
}
cout<}
cout<system("pause");
return0;
}
Question-6
#include
#include
#include
#include
usingnamespacestd;
inta[102][102];
intmain()
{
inti,j,k,m,r,c,max,temp,z,n;
cout<<"请输入待测矩阵个数n:
";
cin>>n;
for(intcount=0;count{
cout<<"输入第"<";
cin>>r;
cout<cout<<"输入第"<";
cin>>c;
for(i=1;i<=r;i++)
{
for(j=0;j{
cin>>a[i][j];
a[i][j]=a[i][j]+a[i-1][j];
}
}
for(i=1,m=a[1][0];i<=r;i++)
for(j=i;j<=r;j++)
{
for(k=max=0;k{
temp=a[j][k]-a[i-1][k];
max=(max>=0?
max:
0)+temp;
m=max>m?
max:
m;
}
}
cout<<"矩阵的最大和为:
"<}
cout<<"输入任意字符结束...";
cin>>z;
}
Question-7
#include
#include
#include
intfight[501][501],meet[501][501],n;//fight[i][j]:
i与jPK能否获胜,meet[i][j]:
i,j能否遇到
intmain()
{
printf("请输入测试数据的组数和决斗的总人数:
\n");
inti,j,k,m,t,cnt