算法实验报告.docx
- 文档编号:23422008
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:30
- 大小:483.90KB
算法实验报告.docx
《算法实验报告.docx》由会员分享,可在线阅读,更多相关《算法实验报告.docx(30页珍藏版)》请在冰豆网上搜索。
算法实验报告
中南大学
算法实验
班级信息安全0901
学生王树雄
学号0909090128
教师冯启龙
【实验内容】
1.实现求n皇后问题和子集和数问题的回溯算法。
2.用动态规划的方法实现0/1背包问题。
3.用分支限界法实现0/1背包问题。
4.用深度优化的方法遍历一个图,并判断图中是否有回路存在,如果有,请输出回路。
【实验要求】
所有的输入和输出都用文件处理。
【题目分析】
(1)N皇后问题
N×N皇后问题的求解过程就是一个试探回逆的过程
1、首先查找第一行的可放位置,第一行全部可以放,那么我们就先将第一个皇后放在(0,0)点。
2、再查找第二行,由于第一行的(0,0)已经放了皇后,故第二行的(1,0)和(1,1)都能放皇后了,可放的就是(1,2)和(1,3)点,在(1,2)放上皇后。
3、再查找第三行,查找所以发现第三行没有可放的位置了,回逆到第二行讲皇后放到(1,3)再查找第3行。
如果还不行,就回到第一行将第一行的皇后放人下一个可放的点,依次类推,查找N×N上的所以可放的位置,直到第一行所以位置被放完,输出结果。
4、根据上面的规律可以发现,对于一个皇后放在坐标(x,y),它的下一行位置为(x-1,y)(x,y)(x+1,y)的坐标都不能再放皇后。
我们用一个数组来存放本行能放皇后的点。
用循环来查找上面行对本行的影响,将收到影响的点置FAlSE。
代码:
#include
#include
#include
#defineN4//N皇后
typedefintChessboard[N+1][N+1];//第0号位置不用
intcount=0;
boolcheck(Chessboardcb,inti,intj){//看棋盘cb是否满足合法布局
inth,k;
intm=i+j,n=i-j;
for(h=1;h
if(cb[h][j]==1&&h!
=i)returnfalse;//检查第j列
if(m-h<=N&&cb[h][m-h]==1&&h!
=i)returnfalse;//检查斜的,m-h<=N是为了保证不越界
if(h-n<=N&&cb[h][h-n]==1&&h!
=i)returnfalse;//检查斜的,h-n<=N是为了保证不越界
}
for(k=1;k =j)returnfalse; returntrue; } voidprintfChessboard(Chessboardcb){//打印棋盘 inti,j; FILE*stream=fopen("a.txt","a"); fprintf(stream,"%s%d%s","(",count,")"); fputs("\n",stream); for(i=1;i<=N;i++){ for(j=1;j<=N;j++){ printf("%d",cb[i][j]); fprintf(stream,"%d",cb[i][j]); } fputs("\n",stream); printf("\n"); } fputs("\n",stream); fclose(stream); printf("\n"); } /*进入本函数时,在n*n棋盘前n-1行已放置了互不攻击的i-1个棋子。 现从第i行起继续为后续棋子选择合适位置。 当i>n时,求得一个合法的布局,输入之。 */ voidtrial(inti,Chessboard&cb){ intj; if(i>N){ count++; printfChessboard(cb); } else{ for(j=1;j<=N;j++){ cb[i][j]=1; if(check(cb,i,j))trial(i+1,cb); cb[i][j]=0; } } } intmain(){ inti,j; Chessboardcb; for(i=1;i<=N;i++)for(j=1;j<=N;j++)cb[i][j]=0;//必须初始化,它的默认值不是0 trial(1,cb); system("pause"); return0; } (效果图) 当为4个皇后的时候 当为5个皇后的时候 子集和数问题 #include #include #defineM31 #defineN4//集合元素个数 intw[N]={13,11,24,7}; intx[N]; voidSubset(ints,intk)//解子集和数问题函数 { inti,l;l=0;x[l]=k; while(l>=0) { while(s+w[x[l]-1] { s=s+w[x[l]-1]; k++;l++; x[l]=k; } while(s+w[x[l]-1]>M&&k<=N) { k++;x[l]=k; } if(s+w[x[l]-1]==M) {k++; for(i=0;i<=l;i++) printf("%d",x[i]);//输出变长解向量 printf("\n"); } while(k>N)//返回上一个节点,实现回溯的主要思想 { l--;k=x[l];x[l]=k+1;s=0; for(i=0;i { s=s+w[x[i]-1]; } } } } 思想也是用到回溯法。 intmain() { printf("数字代表组成结果所在的元素位置\n"); Subset(0,1);//调用subset(ints,intk)函数 system("pause"); return0; } 运行效果: (2)动态规划0/1背包 这是最基础的背包问题,特点是: 每种物品仅有一件,可以选择放或不放。 用子问题定义状态: 即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。 则其状态转移方程便是: f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} 这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。 所以有必要将它详细解释一下: “将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。 如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。 #include #include #defineN50 intmain() { intp[N],w[N],m[N][5*N]; inti,j,c,cw,n,sw,sp; printf("请输入元素个数n: \n"); scanf("%d",&n); printf("请输入背包容量c: \n"); scanf("%d",&c); for(i=1;i<=n;i++) { printf("输入第%d个元素的重量和价值: \n",i); scanf("%d",&w[i]); scanf("%d",&p[i]); } for(j=0;j<=c;j++) if(j>=w[n]) m[n][j]=p[n]; else m[n][j]=0; for(i=n-1;i>=1;i--) for(j=0;j<=c;j++) if(j>=w[i]&&m[i+1][j] m[i][j]=m[i+1][j-w[i]]+p[i]; else m[i][j]=m[i+1][j]; cw=c; printf("\n"); printf("\n"); printf("背包所装物品: \n"); printf("iW[i]p[i]\n"); for(sp=0,sw=0,i=1;i<=n-1;i++) if(m[i][cw]>m[i+1][cw]) { cw-=w[i];sw+=w[i];sp+=p[i]; printf("%2d%3d%3d\n",i,w[i],p[i]); } if(m[1][c]-sp==p[n]) { sw+=w[i];sp+=p[i]; printf("%2d%3d%3d\n",n,w[n],p[n]); } printf("w=%d,pmax=%d\n",sw,sp); printf("\n"); printf("\n"); system("pause"); return0; } #include #include #defineMAXNUM100 structnode{ intstep; doubleprice; doubleweight; doublemax,min; unsignedlongpo; }; typedefstructnodeDataType; structSeqQueue{/*顺序队列类型定义*/ intf,r; DataTypeq[MAXNUM]; }; typedefstructSeqQueue*PSeqQueue; PSeqQueuecreateEmptyQueue_seq(void){ PSeqQueuepaqu; paqu=(PSeqQueue)malloc(sizeof(structSeqQueue)); if(paqu==NULL) printf("Outofspace! ! \n"); else paqu->f=paqu->r=0; returnpaqu; } intisEmptyQueue_seq(PSeqQueuepaqu){ returnpaqu->f==paqu->r; } voidenQueue_seq(PSeqQueuepaqu,DataTypex){ if((paqu->r+1)%MAXNUM==paqu->f) printf("Fullqueue.\n"); else{ paqu->q[paqu->r]=x; paqu->r=(paqu->r+1)%MAXNUM; } } 分支界限法背包 /*删除队列头元素*/ voiddeQueue_seq(PSeqQueuepaqu){ if(paqu->f==paqu->r) printf("EmptyQueue.\n"); else paqu->f=(paqu->f+1)%MAXNUM; } /*对非空队列,求队列头部元素*/ DataTypefrontQueue_seq(PSeqQueuepaqu){ return(paqu->q[paqu->f]); } /*物品按性价比从新排序*/ voidsort(intn,doublep[],doublew[]){ inti,j; for(i=0;i for(j=i;j doublea=p[j]/w[j]; doubleb=p[j+1]/w[j+1]; if(a doubletemp=p[j]; p[j]=p[j+1]; p[j+1]=temp; temp=w[j]; w[j]=w[j+1]; w[j+1]=temp; } } } /*求最大可能值*/ doubleup(intk,doublem,intn,doublep[],doublew[]){ inti=k; doubles=0; while(i m-=w[i]; s+=p[i];if(i s+=p[i]*m/w[i]; i++; } returns; } /*求最小可能值*/ doubledown(intk,doublem,intn,doublep[],doublew[]){ inti=k; doubles=0; while(i m-=w[i]; s+=p[i]; i++; } returns; } /*用队列实现分支定界算法*/ doublesolve(doublem,intn,doublep[],doublew[],unsignedlong*po){ doublemin; PSeqQueueq=createEmptyQueue_seq(); DataTypex={0,0,0,0,0,0}; sort(n,p,w); x.max=up(0,m,n,p,w); x.min=min=down(0,m,n,p,w); if(min==0)return-1; enQueue_seq(q,x); while(! isEmptyQueue_seq(q)){ intstep; DataTypey; x=frontQueue_seq(q); deQueue_seq(q); if(x.max step=x.step+1; if(step==n+1)continue; y.max=x.price+up(step,m-x.weight,n,p,w); if(y.max>=min){ y.min=x.price+down(step,m-x.weight,n,p,w); y.price=x.price; y.weight=x.weight; y.step=step; y.po=x.po<<1; if(y.min>=min){ min=y.min; if(step==n)*po=y.po; } enQueue_seq(q,y); } if(x.weight+w[step-1]<=m){ y.max=x.price+p[step-1]+ up(step,m-x.weight-w[step-1],n,p,w); if(y.max>=min){ y.min=x.price+p[step-1]+ down(step,m-x.weight-w[step-1],n,p,w); y.price=x.price+p[step-1]; y.weight=x.weight+w[step-1]; y.step=step; y.po=(x.po<<1)+1; if(y.min>=min){ min=y.min; if(step==n)*po=y.po; } enQueue_seq(q,y); } } } returnmin; } #definen4 doublem=15; doublep[n]={10,10,12,18}; doublew[n]={2,4,6,9}; intmain(){ inti; doubled; unsignedlongpo; d=solve(m,n,p,w,&po); if(d==-1) printf("Nosolution! \n"); else{ for(i=0;i printf("x%dis%d\n",i+1,((po&(1<<(n-i-1)))! =0)); printf("Themaxweightis%f\n",d); } getchar(); system("pause"); return0; } i++; } if(i s+=p[i]*m/w[i]; i++; } returns; } /*求最小可能值*/ doubledown(intk,doublem,intn,doublep[],doublew[]){ inti=k; doubles=0; while(i m-=w[i]; s+=p[i]; i++; } returns; } /*用队列实现分支定界算法*/ doublesolve(doublem,intn,doublep[],doublew[],unsignedlong*po){ doublemin; PSeqQueueq=createEmptyQueue_seq(); DataTypex={0,0,0,0,0,0}; sort(n,p,w); x.max=up(0,m,n,p,w); x.min=min=down(0,m,n,p,w); if(min==0)return-1; enQueue_seq(q,x); while(! isEmptyQueue_seq(q)){ intstep; DataTypey; x=frontQueue_seq(q); deQueue_seq(q); if(x.max step=x.step+1; if(step==n+1)continue; y.max=x.price+up(step,m-x.weight,n,p,w); if(y.max>=min){ y.min=x.price+down(step,m-x.weight,n,p,w); y.price=x.price; y.weight=x.weight; y.step=step; y.po=x.po<<1; if(y.min>=min){ min=y.min; if(step==n)*po=y.po; } enQueue_seq(q,y); } if(x.weight+w[step-1]<=m){ y.max=x.price+p[step-1]+ up(step,m-x.weight-w[step-1],n,p,w); if(y.max>=min){ y.min=x.price+p[step-1]+ down(step,m-x.weight-w[step-1],n,p,w); y.price=x.price+p[step-1]; y.weight=x.weight+w[step-1]; y.step=step; y.po=(x.po<<1)+1; if(y.min>=min){ min=y.min; if(step==n)*po=y.po; } enQueue_seq(q,y); }}} returnmin; } #definen4 doublem=15; doublep[n]={10,10,12,18}; doublew[n]={2,4,6,9}; intmain(){ inti; doubled; unsignedlongpo; d=solve(m,n,p,w,&po); if(d==-1) printf("Nosolution! \n"); else{ for(i=0;i printf("x%dis%d\n",i+1,((po&(1<<(n-i-1)))! =0)); printf("Themaxweightis%f\n",d); } getchar(); system("pause"); return0; } 实验效果: 1代表该元素被用到,0代表没有用到 (3)深度优先遍历图 从图中某个顶点V0出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到,若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。 当以邻接表作存储结构时,深度优先搜索遍历图的时间复杂度为O(n+e)。 #include #include #include #defineMaxVetexNum10 #defineSTACKINITSIZE30 typedefstruct{ int*base; int*top; intstacksize; }SqStack; typedefstructArcell{ int
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 实验 报告