現在有五個人,五本書,每個人喜歡的書籍不一樣,每個人可能喜歡多本書籍,編寫一個程序,輸入爲這五個人喜歡的書的情況,爲一串以空格隔開的0和1,1代表喜歡,0代表不喜歡,每個人有五個數字,求滿足所有人的方案,輸出這些方案
輸入如下 :
0 0 1 1 0
1 1 0 0 1
0 1 1 0 1
0 0 0 1 0
0 1 0 0 1
代碼如下 :
import java.util.*;
public class HuiSuFivePeople {
static int[][] hobbies = new int[5][5];
static int[] result = {-1,-1,-1,-1,-1};
static int[] visit = {-1,-1,-1,-1,-1};
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
hobbies[i][j] = sc.nextInt();
}
}
tryNext(0);//從第一個人開始嘗試分配書籍
}
public static void tryNext(int num){
for(int i=0;i<5;i++){ //遍歷每一本書
if(hobbies[num][i] == 1&&visit[i]==-1){//假如這本書第num個人喜好並且沒有被分配掉
result[num] = i+1; //分配第i本數給這個人,爲了最後看的方便我增加了1,因爲索引起始爲0
visit[i] = 1; //標記這本書已經被分配了
if(num==4){ //如果最後一個人也分配到了書籍的話,就找到了一種解決方案,輸出方案
System.out.println("找到了一種解決方案,如下");
for(int j=0;j<5;j++){
System.out.print(result[j]+" ");
}
System.out.println();
}else{
tryNext(num+1); //如果沒有分配完成,就嘗試分配下一本
}
visit[i]=-1; //第i本書之後的分配完成了或者後面有不能分配的,tryNext(num+1)執行後到這裏,取消這次的分配,也就是回溯
result[num] = -1;
}
}
}
}
結果如下:
本題是較爲簡單的回溯法的題目,設計起來較爲簡單,其實本題中回溯就是利用遞歸在枚舉中增加了遇到錯誤情況就直接跳過,嘗試下一種循環,比如這題中,如果直接枚舉就是枚舉出所有的書籍分配方案,然後判斷每種方案是否可以,可以就輸出,雖然也可以做,但是很浪費,但是用了回溯,先從第一本書開始嘗試,假如到了第i本無法分配了,那麼第i本之後就不分配了,分配了也是錯的,直接回溯到分配第i-1本,讓第i-1本嘗試分配下一本書,然後嘗試分配第i本書,看看能否分配,假如分配到最後一本了,證明已經分配好了所有書,那麼就輸出結果就可以了,一直這樣直到所有的書都已經分配過了所有可行的方案,就結束枚舉。
這麼做的還有一個好處,輸出的方案,書籍的序號組成的數字串,所有方案的輸出順序是按照從字符串小的到字符串大的輸出的。
下面,總結一下回溯法的基本套路
我做的回溯法都是用遞歸來做的,我的遞歸基本結構如下
public static void dfs(int n(走第n步) ){
for(遍歷所有可以走的選擇){
if(如果這一步可以走){
走起。。。。。。(一般在結果中走這一步,並且標記選擇)
if(如果走到了最後一步){
得到了一種方案,記錄下來
}else{ //如果沒有走到最後一步
dfs(n+1(走下一步));
}
回溯,將剛纔 走起 的操作回退
}
}
}
回溯的大部分問題都可以照着這個結構解決