一个回溯算法问题求解

acyexin 2010-02-27 11:23:04
【例1】从1到X这X个数字中选出N个,排成一列,相邻两数不能相同, 求所有可能的排法。每个数可以选用零次、一次或多次。例如,当N=3、X=3时,排法有12种:121、123、131、132、212、213、231、232、312、313、321、323。
这是百度回溯算法时候得到的一个问题,但是不是用JAVA写的,各位大虾有什么思路吗?
...全文
255 17 打赏 收藏 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
musiclee 2010-03-01
  • 打赏
  • 举报
回复
引用 7 楼 musiclee 的回复:
我明天写,。。。。。。。。。。。。

哈哈 实现我的诺言 。。
思想不变
搜索+树的深度遍历,条件为
1, 节点的孩子不能节点相同,
2, N来控制树的深度,
3, 树的根节点为1...X中不重复的元素(这样保证搜索的结果为所有可能集合)
代码如下(加了注释)

import java.util.ArrayList;

public class Sort {

/**
* 回溯法:
* 从1到X这X个数字中选出N个,排成一列,相邻两数不能相同,
* 求所有可能的排法。每个数可以选用零次、 一次或多次。
* 例如,当N=3、X=3时,排法有12种:
* 121、123、131、132、212、213、231、232、312、313、321、323
*/
public static void main(String[] args) {
int X=5;
int N=4;
//要求解数组
int[] src=new int[X];
//标记数组table[index]=false表示index位置的元素可以选用,true则为已被占用
//主要解决相同元素不能相邻的问题
boolean[] table=new boolean[src.length];

//存放结果List
ArrayList<Integer> resArrayList = new ArrayList<Integer>();
//初始化数组
initArray(src, src.length);

//回溯法遍历求解
SortArray(src, table, N, resArrayList, 0);

}
public static int initArray(int[] srcArray,int X)
{
//初始化目标数组 1...X
if(srcArray.length!=X)
{
return -1;
}
for(int i=0;i<X;i++)
{
srcArray[i]=i+1;
}
return 0;
}

public static void SortArray(int[] srcArray,boolean[] signTable,int N,ArrayList<Integer> resList,int deep)
{
//当遍历到达叶子节点(一次深度搜索已完成) 打印结果
if(deep==N)
{
for(int tI=0;tI<resList.size();tI++)
{
System.out.print(resList.get(tI)+" ");
}
System.out.println();
return ;
}else{

//备份标记数组
boolean[] mySignTable=new boolean[signTable.length];
System.arraycopy(signTable, 0, mySignTable, 0, signTable.length);
if(deep>1)
{
//恢复上上次所选可选性
//及为了保证儿子节点和双亲节点不能相同
mySignTable[resList.get(deep-2)-1]=false;
}

for(int i=0;i<mySignTable.length;i++)
{
//找到第一个为false元素 当做双亲节点
int index=sreachZero(mySignTable,i);
if(index!=-1)
{
//下次以此flase元素为起点查找下一个false元素
//及查找此节点的兄弟节点
i=index;
//第一个结果压栈
resList.add(srcArray[index]);
//标记第此元素以被选用
mySignTable[index]=true;
//递归其子节点
SortArray(srcArray, mySignTable, N, resList, deep+1);
//完成一次深度搜索后进行下一次 及遍历其兄弟节点
//清空本次结果
resList.remove(resList.size()-1);
//清空本次标记
mySignTable[index]=false;
}else {
return;
}

}
}
}

public static int sreachZero(boolean[] signTable,int Offset)
{
//重offset的位置开始在signTable中找第一个出现false的位置
int index=-1;
for(int i=Offset;i<signTable.length;i++)
{
if(!signTable[i])
{
index=i;
return index; //返回第一出现false的index
}
}
return index;
}
public static int getZeroNum(boolean [] signTable)
{
//返回signTable中false的个数(PS:这个方法没用的,但我舍不得删)
int num=0;
for(int i=0;i<signTable.length;i++)
{
if(!signTable[i])
{
num++;
}
}
return num;

}

}
magic_han 2010-03-01
  • 打赏
  • 举报
回复
比较复杂啊,考虑的情况很多
acyexin 2010-03-01
  • 打赏
  • 举报
回复
由于装的是JDK1.4 所以12楼的我没测 13楼的我测了下 没什么问题 感谢各位的跟帖 !
keeya0416 2010-03-01
  • 打赏
  • 举报
回复
【例1】从1到X这X个数字中选出N个,排成一列,相邻两数不能相同, 求所有可能的排法。每个数可以选用零次、一次或多次。例如,当N=3、X=3时,排法有12种:121、123、131、132、212、213、231、232、312、313、321、323。

题目有歧义啊,例如,当N=3、X=3时,排法有12种,1到3中选3个,每个数可以选用零次,一次,或多次 那是不是可以排列成 12121212121212121212.。。等等
zliuzz 2010-03-01
  • 打赏
  • 举报
回复
排列组合= =n
普通的深度优先搜索就可以解决。。。
for(1~n){
长度大于> continue
< 保存 继续递归
}
验证码识别 2010-03-01
  • 打赏
  • 举报
回复
这类问题,语言不重要
mine_meme 2010-03-01
  • 打赏
  • 举报
回复


恩,我进来学习了。这个算法好
eleven_wolf 2010-03-01
  • 打赏
  • 举报
回复
x:所拥有数的个数,n:取出数的个数,no:一共可组成的排列数
在Test()构造方法中给x,n,no赋值,并决定i[][]的范围i[no][n]

我的思路是让排列组成一定的规律,即从小到大进行排列,也就是和楼主列出的顺序是一样的。
这样,给定二维数组i中的任意序列,i[a][b]也就是第a种排列的第b个数是多少?用一种方法给出,即
getInt(int a,int b)方法。也就可以算出所有可能的组合了。
eleven_wolf 2010-03-01
  • 打赏
  • 举报
回复

public class Test {
public int x,n,no;
public int[][] i;
public Test(int x,int n) {
if(n>x || n<1)
return;
this.x = x;
this.n = n;
int no = x;
for(int j=1;j<n;j++) {
no = no *(x-1);
}
this.no = no;
this.i = new int[no][n];
}
public int getInt(int a,int b) {
if(b == 0) {
return a/(int)Math.pow(x-1,n-1) + 1;
} else {
int i = a%(int)Math.pow(x-1,n-b)/(int)Math.pow(x-1,n-1-b) + 1;
if(i >= getInt(a,b-1))
i = i + 1;
return i;
}
}
public static void main(String[] args) {
Test t = new Test(3,3);
for(int a=0;a<t.no;a++) {
for(int b=0;b<t.n;b++) {
t.i[a][b] = t.getInt(a,b);
System.out.print(t.i[a][b]+" ");
}
System.out.println();
}
}
}
acyexin 2010-02-28
  • 打赏
  • 举报
回复
最近抽空看了下以前的一些经典算法,比如老鼠走迷宫,八皇后,骑士,背包等问题,深刻的认为递归和回溯是比较有难度的东西,哪位大虾有兴趣能给几个例子,并且在代码里面写上详细注释,可以让小弟们学习下!^_^
musiclee 2010-02-28
  • 打赏
  • 举报
回复
我明天写,。。。。。。。。。。。。
acyexin 2010-02-28
  • 打赏
  • 举报
回复
有人能给个具体的代码吗?不管用什么思路,出来就行?
py330316117 2010-02-28
  • 打赏
  • 举报
回复
数学中的排列组合问题,和java没多大关系,如果知道数学中的解法(其实就是我们说的算法),基本上就是数组中的操作了。
这题你就用排列组合想一下问题基本上就解决了。实在不行就枚举法,所有可能都列出来
musiclee 2010-02-28
  • 打赏
  • 举报
回复
搜索+树的深度遍历,条件为
1, 节点的孩子不能节点相同,
2, N来控制树的深度,
3, 树的根节点为1...X中不重复的元素(这样保证搜索的结果为所有可能集合)
星辰企业 2010-02-28
  • 打赏
  • 举报
回复
这是数学当中的选择! 要用java代码实现确实要考虑许多的问题!

如果是有重复数字的时候要考虑的方式与没有重复数字的方式需要分类进行考虑!

还有就是选择的个数也不确实! 这个比较麻烦不是简单的for循环就能弄出来的!

支持楼主!
canoe982 2010-02-28
  • 打赏
  • 举报
回复
这是个排列组合的问题啊。总共有
X*(X-1)^(N-1)种排法。
acyexin 2010-02-28
  • 打赏
  • 举报
回复
没人说两句吗?自己顶下!

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧