算法设计与分析实验.docx
《算法设计与分析实验.docx》由会员分享,可在线阅读,更多相关《算法设计与分析实验.docx(19页珍藏版)》请在冰豆网上搜索。
![算法设计与分析实验.docx](https://file1.bdocx.com/fileroot1/2023-4/19/cca855a1-60c6-402a-8371-4144fdab564e/cca855a1-60c6-402a-8371-4144fdab564e1.gif)
算法设计与分析实验
IntegerFactorization
Description
问题描述:
大于1的正整数n可以分解为:
n=X1*X2*…*Xm。
例如,当n=12时,共有8种不同的分解式:
12=12;
12=6*2;
12=4*3;
12=3*4;
12=3*2*2;
12=2*6;
12=2*3*2;
12=2*2*3。
编程任务:
对于给定的正整数n,编程计算n共有多少种不同的分解式。
Input
输入由多组测试数据组成。
每组测试数据输入第一行有1个正整数n(1≤n≤2000000000)。
Output
对应每组输入,输出计算出的不同的分解式数。
SampleInput
12
SampleOutput
8
程序如下:
#include
#include
structDP
{
intnum;
intsum;
}d[50000]={0};
intmax=0;
voidqsort(intlow,inthigh,structDPkey[])
{
inti=low,j=high;
structDPtag=key[i];
if(i{
do
{
while(tag.numif(i{
key[i]=key[j];
i++;
while(tag.num>=key[i].num&&iif(i{
key[j]=key[i];
j--;
}
}
}while(ikey[i]=tag;
qsort(low,j-1,key);
qsort(i+1,high,key);
}
}
intdfs(intleft)
{
inti,p;
intl,r,m;
intcount=0;
l=0;r=max;
while(l<=r)
{
m=(l+r)>>1;
if(d[m].num}
p=l;if(d[p].sum)returnd[p].sum;
for(i=1;i<=d[i].num;i++)
{
if(left%d[i].num==0)count+=dfs(left/d[i].num);
}
d[p].sum=count;
returncount;
}
intmain(void)
{
inti,j,tmp;
intn;
scanf("%d",&n);
tmp=sqrt(n);
for(i=1;i<=tmp;i++)
{
if(n%i==0)
{
d[max].num=i;max++;
d[max].num=n/i;max++;
}
}max--;
qsort(0,max,d);
d[0].sum=1;
printf("%d\n",dfs(n));
return0;
}
比赛安排
Description
设有2^n(n<=6)个球队进行单循环比赛,计划在2^n–1天内完成,每个队每天进行一场比赛。
设计一个比赛的安排,使在2^n–1天内每个队都与不同的对手比赛。
例如n=2时的比赛安排:
队1234
比赛1==23==4一天
1==32==4二天
1==42==3三天
Input
输入由多组测试数据组成。
每组测试数据输入一个正整数代表题目中的n。
Output
对应每组输入,输出如样例所示。
<1>1-2,3-4表示第一天1队与2队,3队与4队比赛
SampleInput
2
SampleOutput
<1>1-2,3-4
<2>1-3,2-4
<3>1-4,2-3
程序如下:
#include
inta[80][80];
voidcopy(intn)
{
intm,i,j;
m=n/2;
for(i=1;i<=m;i++)
for(j=1;j<=m;j++)
{
a[i][j+m]=a[i][j]+m;
a[i+m][j]=a[i][j+m];
a[i+m][j+m]=a[i][j];
}
}
voidwz(intn)
{
if(n==1){a[1][1]=1;return;}
else
wz(n/2);
copy(n);
}
intmain()
{
intn,i,j,m,f,k;
while(scanf("%d",&n)!
=EOF){
k=1;
for(i=0;ik*=2;
wz(k);
m=0;
for(j=2;j<=k;j++){
m++;f=1;
for(i=1;i<=k;i++)
{
if(a[i][j]!
=0){
if(f)
{printf("<%d>%d-%d",m,i,a[i][j]);f=0;}
else
printf(",%d-%d",i,a[i][j]);
a[a[i][j]][j]=0;
}
}
printf("\n");
}
}
}
又是Hanoi塔问题
Description
A、B、C是3个塔座。
开始时,在塔座A上有一叠共n个圆盘,这些圆盘自下而上,由大到小地叠在一起。
各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。
现要求将塔座A上的这一叠圆盘移到塔座B上,并仍按同样顺序叠置。
在移动圆盘时应遵守以下移动规则:
规则
(1):
每次只能移动1个圆盘;
规则
(2):
任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):
任何时刻都不允许将同色圆盘叠在一起;
规则(4):
在满足移动规则
(1)-(3)的前提下,可将圆盘移至A,B,C中任一塔座上。
按照上述四种规则移动过程中,如将圆盘从A柱移到B柱,则称B柱使用一次。
例如要将塔座A上2个圆盘,按上述四种规则移动到B柱,A柱使用0次,B柱使用2次,C柱使用1次。
试设计一个算法,统计用最少的移动次数将塔座A上的n个圆盘移到塔座B上并仍按同样顺序叠置时,A柱、B柱、C柱的使用次数。
编程任务:
对于给定的正整数n,编程计算最优移动方案时,A柱、B柱、C柱的使用次数。
Input
输入由多组测试数据组成。
每组测试数据的第1行是给定的正整数n。
Output
对应每组输入,输出的每一行由三个相互空格的正整数组成,分别表示塔座A的使用次数、塔座B的使用次数及塔座C的使用次数。
SampleInput
2
SampleOutput
021
程序如下:
#include
usingnamespacestd;
classHanoi
{
private:
intnumA,numB,numC;
public:
Hanoi();
voidMoveHanoi(intnum,charA,charB,charC);
voidCaluater(charch1,charch2);
voidDisplay();
};
Hanoi:
:
Hanoi()
{
numA=0;
numB=0;
numC=0;
}
voidHanoi:
:
Caluater(charch1,charch2)
{
if(ch2=='A')
numA++;
elseif(ch2=='B')
numB++;
else
numC++;
}
voidHanoi:
:
MoveHanoi(intnum,charA,charB,charC)
{
if(num>0)
{
MoveHanoi(num-1,A,C,B);
Caluater(A,B);
MoveHanoi(num-1,C,B,A);
}
}
voidHanoi:
:
Display()
{
cout<}
intmain()
{
intnn;
while(cin>>nn)
{
Hanoih;
h.MoveHanoi(nn,'A','B','C');
h.Display();
}
return0;
}
PermutationwithRepetition
Description
R={r1,r2,…,rn}是要进行排列的n个元素。
其中元素r1,r2,…,rn可能相同。
试设计一个算法,列出R的所有不同排列。
编程任务:
给定n以及待排列的n个元素。
计算出这n个元素的所有不同排列。
Input
输入由多组测试数据组成。
每组测试数据的第1行是元素个数n,1<=n<=500。
接下来的1行是待排列的n个元素。
Output
对应每组输入,将计算出的n个元素的所有不同排列输出,每种排列单独一行。
最后1行中的数是排列总数。
SampleInput
4
aacc
SampleOutput
aacc
acac
acca
caac
caca
ccaa
6
程序如下:
#include
#include
usingnamespacestd;
intans;
intok(charstr[],inta,intb)
{
if(b>a)
for(inti=a;i
if(str[i]==str[b])
return0;
return1;
}
voidperm(charstr[],intk,intm)
{
inti;
if(k==m)
{
ans++;
for(i=0;i<=m;i++)
{
printf("%c",str[i]);
}
printf("\n");
}
else
{
for(i=k;i<=m;i++)
if(ok(str,k,i))
{
swap(str[k],str[i]);
perm(str,k+1,m);
swap(str[k],str[i]);
}
}
}
intmain(intargc,char*argv[])
{
charstr[1000];
intn;
while(scanf("%d",&n)!
=EOF)
{
ans=0;
scanf("%s",str);
perm(str,0,n-1);
printf("%d\n",ans);
}
return0;
}
ProblemC:
整数划分问题
Description
将正整数n表示成一系列正整数之和:
n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥1,k≥1。
正整数n的这种表示称为正整数n的划分。
求正整数n的不同划分个数。
例如正整数6有如下11种不同的划分:
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1。
Input
输入包含n+1行;
第一行是一个整数n,表示有n个测试用例;
第2至n+1每行一个正整数。
Output
对应每组输入,输出正整数n的不同划分个数。
SampleInput
2
5
6
SampleOutput
7
11
程序如下:
#include
intsplit(intn,intm);
intmain()
{
intk,i;
inta[100];
scanf("%d",&k);
for(i=0;i{scanf("%d",&a[i]);
}
for(i=0;i{printf("%d\n",split(a[i],a[i]));
}
}
intsplit(intn,intm)
{
if((n<1)||(m<1))return0;
if((n==1)||(m==1))return1;
if(nif(n==m)returnsplit(n,m-1)+1;
returnsplit(n,m-1)+split(n-m,m);
}
双色Hanoi塔问题
Description
A、B、C是3个塔座。
开始时,在塔座A上有一叠共n个圆盘,这些圆盘自下而上,由大到小地叠在一起。
各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。
现要求将塔座A上的这一叠圆盘移到塔座B上,并仍按同样顺序叠置。
在移动圆盘时应遵守以下移动规则:
规则
(1):
每次只能移动1个圆盘;
规则
(2):
任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):
任何时刻都不允许将同色圆盘叠在一起;
规则(4):
在满足移动规则
(1)-(3)的前提下,可将圆盘移至A,B,C中任一塔座上。
试设计一个算法,用最少的移动次数将塔座A上的n个圆盘移到塔座B上,并仍按同样顺序叠置。
编程任务:
对于给定的正整数n,编程计算最优移动方案。
Input
输入由多组测试数据组成。
每组测试数据的第1行是给定的正整数n。
Output
对应每组输入,输出的每一行由一个正整数k和2个字符c1和c2组成,表示将第k个圆盘从塔座c1移到塔座c2上。
SampleInput
3
SampleOutput
1AB
2AC
1BC
3AB
1CA
2CB
1AB
程序如下:
#include
intsplit(intn,intm);
intmain()
{
intk,i;
inta[100];
scanf("%d",&k);
for(i=0;i{scanf("%d",&a[i]);
}
for(i=0;i{printf("%d\n",split(a[i],a[i]));
}
}
intsplit(intn,intm)
{
if((n<1)||(m<1))return0;
if((n==1)||(m==1))return1;
if(nif(n==m)returnsplit(n,m-1)+1;
returnsplit(n,m-1)+split(n-m,m);
}
再次hanoi塔问题
Description
古老的汉诺塔问题是:
用最少的步数将N个半径互不相等的圆盘从l号柱利用2号柱全部移动到3号柱,在移动的过程中小盘要始终在大盘的上面。
现在再加上一个条件:
不允许直接把盘从l号柱移动到3号柱,也不允许直接把盘从3号柱移动到1号柱。
把盘按半径从小到大用1~N编号。
每种状态用N个整数表示,第i个整数表示i号盘所在的柱的编号。
则N=2时的移动方案为
(1,1)≥(2,1)≥(3,1)≥(3,2)≥(2,2)≥(1,2)≥(1,3)≥(2,3)≥(3,3)
初始状态为第O步,编程求在某步数时的状态。
Input
输入的第1行为整数T(1≤T≤50000),表示输入数据的组数。
接下来的丁行,每行有两个整数N,M(1≤N≤19,O≤M≤移动N个圆盘所需的步数)。
Output
输出共有T行。
对于每组输入数据,输出N个整数表示移动N个盘在M步时的状态,每两个数之间用一个空格隔开,行首和行末不要有多余的空格。
SampleInput
4
20
25
30
31
SampleOutput
11
12
111
211
程序如下:
#include
usingnamespacestd;
intf[20],ans[20];
voidCompute(intn,intm,ints,intanx,intd)
{
if(n==0)
return;
if(m<=f[n-1])
{
ans[n]=s;
Compute(n-1,m,s,anx,d);
return;
}
if(m<=2*f[n-1]+1)
{
ans[n]=anx;
Compute(n-1,m-(f[n-1]+1),d,anx,s);
return;
}
ans[n]=d;
Compute(n-1,m-(2*f[n-1]+2),s,anx,d);
return;
}
intmain()
{
intt,n,m,i;
f[0]=0;
for(i=1;i<=19;i++)
f[i]=f[i-1]*3+2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
Compute(n,m,1,2,3);
for(i=1;i<=n;i++)
printf(i==1?
"%d":
"%d",ans[i]);
printf("\n");
}
return0;
}