有7个和尚,一星期七天每天安排一个和尚挑水,每个和尚在每周中空闲的时间不一。用一个二维数组M[][]来表示7个和尚在7天中是否可以挑水,M[i][j]==1表示第i个和尚在第j天可以挑水,M[i][j]==0表示第i个和尚在第j天不可以挑水。现输入矩阵M,要求求出方案的总数,并逐天输出挑水的和尚。
可以考虑用回溯法解决该问题,第i天选取符合条件的和尚j挑水,则和尚j不能在其他的天里挑水,设置visited[j]=1,第i+1天若存在可挑水的和尚,则选取,若不存在,则返回第i天,选取非j和尚挑水。可以利用递归来实现回溯。
import java.util.*;
public class Arrange {
static int M[][] = new int[8][8];
static int sum = 0;
static ArrayList<Integer> allArranges = new ArrayList<>();//用来存储所有安排方案
static Integer arrange[] = new Integer[8];//存储当前单个安排方案
static int visited[] = new int[8];//visited[i]的值描述地i个和尚是否被访问过,1表示已被访问,0表示未被访问;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
for(int i=1;i<8;i++){
for(int j=1;j<8;j++){
M[i][j] = in.nextInt();
}
}
in.close();
//初始化
for(int i=1;i<8;i++){
arrange[i]=0;
visited[i]=0;
}
backTrack(1);
//输出方案
System.out.print(sum+"\n");
for(int i=0; i<sum; i++){
for(int j=0; j<7; j++){
System.out.print(allArranges.get(i*7+j)+" ");
}
System.out.println();
}
}
static void backTrack(int t){//用递归来实现回溯,t代表第t天
if(t==8){
for(int i=1; i<8; i++){
allArranges.add(arrange[i]);
}
sum++;
}
else{
for(int i=1;i<8;i++){
if(visited[i]==0 && M[i][t]==1){
arrange[t]=i;
visited[i]=1;
backTrack(t+1);
visited[i]=0;
}
}
}
}
}
示例:
输入:
1 0 0 1 0 1 0
0 0 1 1 0 0 0
0 1 0 0 1 0 1
1 1 0 0 0 1 0
0 0 1 0 1 0 0
0 0 0 1 0 0 1
1 0 0 0 1 0 0
输出
5
1 3 5 2 7 4 6
4 3 5 2 7 1 6
7 3 2 1 5 4 6
7 4 2 6 5 1 3
7 4 5 2 3 1 6