回溯法(1)
2015-11-23 16:17
337 查看
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
组合数是不考虑顺序的,不妨设:
a[r]>a[r-1]>…a[1],
从这里可以看出a[r]>r-1。
算法:
1)取初始状态a[0]=n,i=0.
2)当a[0]>r-1时,重复操作:
如果a[i]>r-i-1:
1.i=r,a[i]=a[i]-1.
2.i!=r,i=i+1,a[i]=a[i-1]-1.
如果a[i]<=r-i-1:
i=i-1,a[i]=a[i]-1.(这一步是回溯)
3)结束.
例如:n=7,k=3,下面三种分法认为是相同的。
1,1,5 1,5,1, 5,1,1
问有多少种不同的分法。
由于不考虑顺序,不妨让分法有递增顺序(即采取1,1,5的表示方法)。
算法:
1)初始状态a[0]=1,i=0,sum=n-1,nk=n/k,t=0
(数组a[k]代表不同分法表示的k个数,t是用来计数有多少种不同分法的,a[0]的值是不能超过nk的,sum表示还剩下多少可以划分,比如n=7,a[0]=1,a[1]=1,这个时候sum=5,因为还有5可以划分)
2)当a[0]<=nk时,重复操作:
如果i=k,则t=t+1,a[i]=sum+a[i],输出数组a,i=i-1,a[i]+1,sum=a[i+1]-1。(回溯)
如果i< k:
1.如果sum>=a[i]:i=i+1,a[i]=a[i-1]
2.如果sum< a[i]:i=i-1,a[i]=a[i]+1 (回溯)
3)输出t,结束。
1.组合问题
从n个数(1,2…n)中选出r个数的组合(不重复).组合数是不考虑顺序的,不妨设:
a[r]>a[r-1]>…a[1],
从这里可以看出a[r]>r-1。
算法:
1)取初始状态a[0]=n,i=0.
2)当a[0]>r-1时,重复操作:
如果a[i]>r-i-1:
1.i=r,a[i]=a[i]-1.
2.i!=r,i=i+1,a[i]=a[i-1]-1.
如果a[i]<=r-i-1:
i=i-1,a[i]=a[i]-1.(这一步是回溯)
3)结束.
public class Combination { public static void main(String args[]){ int n=10,r=5; int i=0,a[]=new int[r]; a[0]=n; while(a[0]>r-1){ if(a[i]>r-i-1){ if(r==i+1){ output(a); a[i]--; } else{ a[i+1]=a[i]-1; i++; } } else{ i--; a[i]--; } } } private static void output(int[] a) { // TODO Auto-generated method stub for(int j=0;j<a.length;j++){ System.out.print(a[j]+""); } System.out.println(); } }
2.数的划分
整数n分成k份,每份不能为空,任意两份不能相同(不考虑顺序)。例如:n=7,k=3,下面三种分法认为是相同的。
1,1,5 1,5,1, 5,1,1
问有多少种不同的分法。
由于不考虑顺序,不妨让分法有递增顺序(即采取1,1,5的表示方法)。
算法:
1)初始状态a[0]=1,i=0,sum=n-1,nk=n/k,t=0
(数组a[k]代表不同分法表示的k个数,t是用来计数有多少种不同分法的,a[0]的值是不能超过nk的,sum表示还剩下多少可以划分,比如n=7,a[0]=1,a[1]=1,这个时候sum=5,因为还有5可以划分)
2)当a[0]<=nk时,重复操作:
如果i=k,则t=t+1,a[i]=sum+a[i],输出数组a,i=i-1,a[i]+1,sum=a[i+1]-1。(回溯)
如果i< k:
1.如果sum>=a[i]:i=i+1,a[i]=a[i-1]
2.如果sum< a[i]:i=i-1,a[i]=a[i]+1 (回溯)
3)输出t,结束。
public class NumberDivide { public static void main(String args[]){ int n=10,k=5; if(k>n){ System.out.println("none"); return; } int nk=n/k,t=0,i=0,sum=n-1; int a[]=new int[k]; a[0]=1; while(a[0]<=nk){ if(i==k-1){ a[i]=sum+a[i]; output(a); i--; a[i]++; sum=a[i+1]-1; t++; } else{ if(sum>=a[i]){ i++; a[i]=a[i-1]; sum=sum-a[i]; } else{ i--; a[i]++; sum=sum+a[i+1]-1; } } } System.out.println(t); } private static void output(int[] a) { // TODO Auto-generated method stub for(int j=0;j<a.length;j++){ System.out.print(a[j]+""); } System.out.println(); } }
3.老鼠走迷宫
问题:有一个迷宫,在迷宫的某个出口放着一块奶酪。将一只老鼠由某个入口处放进去,它必须穿过迷宫,找到奶酪。请找出它的行走路径。class Position{ int x,y; public Position(int x,int y){ this.x=x; this.y=y; } } public class Maze { static int size; static int maze[][]=new int[size+2][size+2]; private static boolean findPath(){ ArrayStack path=new ArrayStack(); Position offset[]=new Position[4]; offset[0]=new Position(0,1); offset[1]=new Position(1,0); offset[2]=new Position(0,-1); offset[3]=new Position(-1,0); for(int i=0;i<=size+1;i++){ maze[0][i]=maze[size+1][i]=1; maze[i][0]=maze[i][size+1]=1; } Position here=new Position(1,1); maze[1][1]=1; int option=0; int lastOption=3; while(here.x!=size||here.y!=size){ int r=0,c=0; while(option<=lastOption){ r=here.x+offset[option].x; c=here.y+offset[option].y; if(maze[r][c]==0) break; option++; } if(option<=lastOption){ path.push(here); here=new Position(r,c); maze[r][c]=1; option=0; } else{ if(path.isEmpty())return false; Position next=(Position) path.pop(); if(next.x==here.x){ option=2+next.y-here.y; } else option=3+next.x-here.x; here=next; } } return true; } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统