問題描述:
某寺廟裏7個和尚:輪流挑水,爲了和其他任務不能衝突,各人將有空天數列出如下表:
和尚1: 星期二,四;
和尚2: 星期一,六;
和尚3: 星期三,日;
和尚4: 星期五;
和尚5: 星期一,四,六;
和尚6: 星期二,五;
和尚7: 星期三,六,日;
請將所有合理的挑水時間安排表
輸入7行7列,0代表和尚今天不挑水,1代表可以挑水,A和尚挑完水本週就不挑了,問有多少種挑水方法,排列組合是什麼。
這題比較糾結的是如何先輸出挑水的總數,然後輸出挑水的安排。如果用回溯法進行遞歸的話,只能count++或者輸出滿足條件的情況,但是肯定不能先輸出總是再輸出安排。我能想到就是比較笨的方法,同一種方法使用兩次,這裏就不寫那種方法了,只寫輸出安排,最後輸出總數的方法,有好方法的話還望賜教。
回到本題,用回溯法做比較方便,週一選出一個合適的和尚,再週二選合適的和尚,直到週末,這個合適指的是和尚該天可以挑水而且之前沒挑過,可以用兩個數組存放其狀態,狀態符合的話就往下走。用遞歸和for循環實現遍歷所以情況,判斷是否適合。程序代碼如下:
#include <iostream>
#define day 8
using namespace std;
int spare[day][day];
int count;
int monk[day];//週一至週末值日的和尚
int done[day];//用來存放和尚在星期day是否值日過
/*
void getNum(int t){
if(t>=day) {
count++;
}
else{
for(int i=1;i<day;i++){
monk[t]=i;
if(done[i]==0 && spare[i][t]==1){
done[i]=1;
getNum(t+1);
done[i]=0;
}
}
}
}
*/
void printmonk(int t){
if(t>=day){
for(int i=1;i<day;i++){
cout<<monk[i]<<" ";
}
cout<<endl;
count++;
}
else{
for(int i=1;i<day;i++){
monk[t]=i;
if(done[i]==0 && spare[i][t]==1){
done[i]=1;
printmonk(t+1);
done[i]=0;
}
}
}
}
int main(){
count=0;
for(int i=1;i<day;i++)
for(int j=1;j<day;j++)
cin>>spare[i][j];
for(int i=1;i<day;i++){
monk[i]=0;
done[i]=0;
}
printmonk(1);
cout<<count<<endl;
//getNum(1);
/*
cout<<count<<endl;
for(int i=1;i<day;i++){
monk[i]=0;
done[i]=0;
}
printmonk(1);
*/
return 0;
}
如有問題,希望提出。