和尚挑水问题
题目描述
某寺庙里7个和尚:轮流挑水,为了和其他任务不能冲突,各人将有空天数列出如下表:
和尚1: 星期二,四;
和尚2: 星期一,六;
和尚3: 星期三,日;
和尚4: 星期五;
和尚5: 星期一,四,六;
和尚6: 星期二,五;
和尚7: 星期三,六,日;
请将所有合理的挑水时间安排表
样例输入:
input:
请输入和尚1的空闲时间:0 1 0 1 0 0 0
请输入和尚2的空闲时间:1 0 0 0 0 1 0
请输入和尚3的空闲时间:0 0 1 0 0 0 1
请输入和尚4的空闲时间:0 0 0 0 1 0 0
请输入和尚5的空闲时间:1 0 0 1 0 1 0
请输入和尚6的空闲时间:0 1 0 0 1 0 0
请输入和尚7的空闲时间:0 0 1 0 0 1 1
样例输出:
output:
方案1:
星期1和尚2挑水
星期2和尚6挑水
星期3和尚3挑水
星期4和尚1挑水
星期5和尚4挑水
星期6和尚5挑水
星期7和尚7挑水
方案2:
星期1和尚2挑水
星期2和尚6挑水
星期3和尚7挑水
星期4和尚1挑水
星期5和尚4挑水
星期6和尚5挑水
星期7和尚3挑水
方案3:
星期1和尚5挑水
星期2和尚6挑水
星期3和尚3挑水
星期4和尚1挑水
星期5和尚4挑水
星期6和尚2挑水
星期7和尚7挑水
方案4:
星期1和尚5挑水
星期2和尚6挑水
星期3和尚7挑水
星期4和尚1挑水
星期5和尚4挑水
星期6和尚2挑水
星期7和尚3挑水
共有4种方案
[解题思路]
很明显的深度优先搜索,在各人有空的表中(二维数组),按天数(列)遍历,发现符合的和尚(行),因为一个和尚只挑依次水,所以标记当前行和当前列为1,表示已用。继续按天数(列)遍历,直到星期7,依次判断和尚是否有空,符合则输出,回溯。
#include<iostream>
using namespace std;
//初始化
const int N=8;
const int D=8;
int table[N][D]={ 0,0,0,0,0,0,0,0,
0,0,1,0,1,0,0,0,
0,1,0,0,0,0,1,0,
0,0,0,1,0,0,0,1,
0,0,0,0,0,1,0,0,
0,1,0,0,1,0,1,0,
0,0,1,0,0,1,0,0,
0,0,0,1,0,0,1,1 };
int note[N][D]={0}; //记录当前值是否可用
int ans[8]; //每个方案的值
int sum=0; //统计多少个方案
//完成输入
void input()
{
for(int i=1;i<N;i++) //行
for(int j=1;j<D;j++) //列
cin>>table[i][j];
}
//输出方案
void output_project()
{
cout<<"方案"<<sum<<":"<<endl;
for(int i=1;i<N;i++)
{
cout<<"星期"<<i<<"和尚"<<ans[i]<<"挑水"<<endl;
}
cout<<endl;
}
//判断是否有时间
bool IsTime()
{
bool flag=true;
for(int i=1;i<N;i++)
{
if(table[ans[i]][i]==1) ; //避免同列,同行;
else
flag=false;
}
return flag;
}
//递归回溯
int dfs(int week)
{
if(week==8) //结束标志
{
if(IsTime()) /*符合条件则输出*/
{
sum++; //方案总数累加
output_project();
}
return 0;
}
for(int i=1;i<N;i++)//行
{
if(note[i][week]==0) //当前值是否符合条件
{
ans[week]=i;
for(int k=1;k<8;k++) //标记 行:i 列:week
{
note[k][week]++;
note[i][k]++;
}
dfs(week+1); //继续拓展下一天
for(int k=1;k<8;k++) //回溯
{
note[k][week]--;
note[i][k]--;
}
}
}
return 0;
}
int main()
{
//input();
dfs(1);
cout<<endl<<"共有"<<sum<<"种方案";
getchar();
return 0;
}
[运行结果]