大多数的回溯算法都是需要填充的和给出的总数是相等的,比如前面提到的N皇后问题,一共给了N个皇后,一共也只需要填充N次;再比如前面提到的方格填数问题,一共10个空格,而给的数也是10个。下面来看两个问题,需要填充的和给出的总数是不相等的。
一、抽签问题
1.题目:
X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。
C国最多可以派出2人。
....
那么最终派往W星的观察团会有多少种国别的不同组合呢?
下面的程序解决了这个问题。
数组a[] 中既是每个国家可以派出的最多的名额。
程序执行结果为:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF
....
(以下省略,总共101行)
2.分析:这里一共需要填充5个,而给出的总数却不只5个,
3.代码如下:
<span style="color:#330099">package 回溯;
public class 抽签
{
private static int count=0;
/*遍历到第k个国家,还剩下n个空位置*/
public static void f(int[] a, int k, int n, String s)
{
if(k==a.length){/*遍历到第6个国家,没有空位*/
count++;
if(n==0)
System.out.println(s);
return;
}
String s2 = s;
//每个国家开始,每个国家出i个人
for(int i=0; i<=a[k]; i++){
f(a, k+1, n-i, s2); //填空位置
s2 += (char)(k+'A');
}
}
public static void main(String[] args)
{
int[] a = {4,2,2,1,1,3};
f(a,0,5,"");
System.out.print(count);
}
} </span>
注:其实这题也可以用上一篇介绍的普通回溯法来求解,设一个a[5]的数组表示待填充的空格,然后a[i]的值可以为A、B、C、D、E,每次填充判断一下A、B、C、D、E的数量有没有超额,和“李白打酒问题”比较相似,只不过这样在判断条件的时候会麻烦一点。
二、牌型种数问题
1.
牌型种数
小明被劫持到X赌城,被迫与其他3人玩牌。
一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。
这时,小明脑子里突然冒出一个问题:
如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?
请填写该整数,不要填写任何多余的内容或说明文字。
2.分析:这里和上一题一样,也是需要填充的(13张)和给出总数不一样(一共52张),不过不同的是,上面一题组合的种数不确定,这里组合的种数是确定的(4个人,即4种)。
3.代码:
<span style="color:#330099">package 回溯;
public class 牌型种数 {
public static int sum = 0;
public static int count = 0;
public static void calculate(int kind)
//kind表示牌的种数,sum表示总人数
{
if(sum>13||kind>13)
return;
if(kind == 13&& sum == 13)
{
count ++;
}
if(kind<13)
{
int i;
for(i=0;i<5;i++)
{
sum += i;
calculate(kind + 1);
sum -= i; //回溯的时候一定要记住还原标记哦!!!!!!
}
}
}
public static void main(String[] args){
calculate(0);
System.out.println(count);
}
}</span>