蓝桥杯 人员排日程 伪DFS
2015-03-24 20:01
197 查看
某保密单位机要人员 A,B,C,D,E 每周需要工作5天,休息2天。
上级要求每个人每周的工作日和休息日安排必须是固定的,不能在周间变更。
此外,由于工作需要,还有如下要求:
1. 所有人的连续工作日不能多于3天(注意:周日连到下周一也是连续)。
2. 一周中,至少有3天所有人都是上班的。
3. 任何一天,必须保证 A B C D 中至少有2人上班。
4. B D E 在周日那天必须休息。
5. A E 周三必须上班。
6. A C 一周中必须至少有4天能见面(即同时上班)。
你的任务是:编写程序,列出ABCDE所有可能的一周排班情况。工作日记为1,休息日记为0
A B C D E 每人占用1行记录,从星期一开始。
【输入、输出格式要求】
程序没有输入,要求输出所有可能的方案。
每个方案是7x5的矩阵。只有1和0组成。
矩阵中的列表示星期几,从星期一开始。
矩阵的行分别表示A,B,C,D,E的作息时间表。
多个矩阵间用空行分隔开。
例如,如下的矩阵就是一个合格的解。请编程输出所有解(多个解的前后顺序不重要)。
0110111
1101110
0110111
1101110
1110110
【注意】
请仔细调试!您的程序只有能运行出正确结果的时候才有机会得分!
在评卷时使用的输入数据与试卷中给出的实例数据可能是不同的。
记得以前学C++的时候,做过一道医生排班的问题,和这道题目略有相似,只不过在做这道题目之前,我们需要一点小小的优化,就是通过题目的描述先推断出一些情况,这样在枚举的时候就可以减少很多循环。
1.推理
如果你在纸上画一画的话,你会发现有一个人很特殊,就是E,根据题目条件,我们知道:E在星期天不上班,而在星期三上班,那么他只有一天的休息,如果放到星期一或星期二,那他星期3,4,5,6就会连着上班,不符合题目条件也就是说星期1,2,也要上班,同样他也不能在星期5或星期6上班,因为那会导致他在星期1,2,3,4上班,所以他只可能在星期4休息,也就是说,他的值班表为1,1,1,0,1,1,0。同样,我们也可以知道B和D在星期天也是休息的,所以我们只要在星期1-6再找一天休息日即可,而A,C两人则必须从星期1-7中找两天休息日。
2.在枚举的时候,本来是想用递归来做,但因为算法不一样,递归难以进行,所以就采用了一种类似递归的算法,只不过把每一层都抽出来了,其实就是4个函数,分别枚举四个人的休息日,然后再层层调用,从而找到每一种情况。
3.判断的时候,有点考验逻辑推理能力,像这种题目,我一般采用正难则反的策略,因为正确的情况很少,而错误的情况多但明显易找,所以我们可以把错误的情况罗列出来,每一次遇到错误就return一个返回值,表示错误,这里,我建议大家不要直接返回true或者false,可以返回1,2,3,4...这样的数字,而且,每一种情况的返回值不同,这样在调试的时候能够很快找到是哪里错了。
#include<iostream>
#include<stdio.h>
using namespace std;
bool P[5][7];
void init()
{
int i,j;
for(i=0;i<5;i++)
{
for(j=0;j<7;j++)
{
P[i][j]=1;
}
}
P[1][6]=0;
P[3][6]=0;
P[4][3]=P[4][6]=0;
}
int judge()
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<7;j++)
{
if(P[i][j%7]==1&&P[i][(j+1)%7]==1&&P[i][(j+2)%7]==1&&P[i][(j+3)%7]==1)
return 1;
}
}
int count=0;
bool flag=true;
for(j=0;j<7;j++)
{
for(i=0;i<5;i++)
{
if(P[i][j]==0)
{
flag=false;
}
}
if(flag)
count++;
flag=true;
}
if(count<3)
return 2;
count=0;
for(j=0;j<7;j++)
{
for(i=0;i<4;i++)
{
if(P[i][j]==1)
count++;
}
if(count<2)
return 3;
count=0;
}
if(P[0][2]==0)
return false;
count=0;
for(j=0;j<7;j++)
{
if(P[0][j]==1&&P[2][j]==1)
count++;
}
if(count<4)
return 4;
return 5;
}
void show()
{
int i,j;
for(i=0;i<5;i++)
{
for(j=0;j<7;j++)
{
cout<<P[i][j]<<' ';
}
cout<<endl;
}
}
void getD()
{
int i;
for(i=0;i<6;i++)
{
P[3][i]=0;
if(judge()==5)
{
show();
cout<<endl;
}
P[3][i]=1;
}
}
void getC()
{
int i,j;
for(i=0;i<7;i++)
{
for(j=i+1;j<7;j++)
{
P[2][i]=P[2][j]=0;
getD();
P[2][i]=P[2][j]=1;
}
}
}
void getB()
{
int i;
for(i=0;i<6;i++)
{
P[1][i]=0;
getC();
P[1][i]=1;
}
}
void getA()
{
int i,j;
for(i=0;i<7;i++)
{
for(j=i+1;j<7;j++)
{
P[0][i]=P[0][j]=0;
getB();
P[0][i]=P[0][j]=1;
}
}
}
int main()
{
init();
getA();
return 0;
}
上级要求每个人每周的工作日和休息日安排必须是固定的,不能在周间变更。
此外,由于工作需要,还有如下要求:
1. 所有人的连续工作日不能多于3天(注意:周日连到下周一也是连续)。
2. 一周中,至少有3天所有人都是上班的。
3. 任何一天,必须保证 A B C D 中至少有2人上班。
4. B D E 在周日那天必须休息。
5. A E 周三必须上班。
6. A C 一周中必须至少有4天能见面(即同时上班)。
你的任务是:编写程序,列出ABCDE所有可能的一周排班情况。工作日记为1,休息日记为0
A B C D E 每人占用1行记录,从星期一开始。
【输入、输出格式要求】
程序没有输入,要求输出所有可能的方案。
每个方案是7x5的矩阵。只有1和0组成。
矩阵中的列表示星期几,从星期一开始。
矩阵的行分别表示A,B,C,D,E的作息时间表。
多个矩阵间用空行分隔开。
例如,如下的矩阵就是一个合格的解。请编程输出所有解(多个解的前后顺序不重要)。
0110111
1101110
0110111
1101110
1110110
【注意】
请仔细调试!您的程序只有能运行出正确结果的时候才有机会得分!
在评卷时使用的输入数据与试卷中给出的实例数据可能是不同的。
记得以前学C++的时候,做过一道医生排班的问题,和这道题目略有相似,只不过在做这道题目之前,我们需要一点小小的优化,就是通过题目的描述先推断出一些情况,这样在枚举的时候就可以减少很多循环。
1.推理
如果你在纸上画一画的话,你会发现有一个人很特殊,就是E,根据题目条件,我们知道:E在星期天不上班,而在星期三上班,那么他只有一天的休息,如果放到星期一或星期二,那他星期3,4,5,6就会连着上班,不符合题目条件也就是说星期1,2,也要上班,同样他也不能在星期5或星期6上班,因为那会导致他在星期1,2,3,4上班,所以他只可能在星期4休息,也就是说,他的值班表为1,1,1,0,1,1,0。同样,我们也可以知道B和D在星期天也是休息的,所以我们只要在星期1-6再找一天休息日即可,而A,C两人则必须从星期1-7中找两天休息日。
2.在枚举的时候,本来是想用递归来做,但因为算法不一样,递归难以进行,所以就采用了一种类似递归的算法,只不过把每一层都抽出来了,其实就是4个函数,分别枚举四个人的休息日,然后再层层调用,从而找到每一种情况。
3.判断的时候,有点考验逻辑推理能力,像这种题目,我一般采用正难则反的策略,因为正确的情况很少,而错误的情况多但明显易找,所以我们可以把错误的情况罗列出来,每一次遇到错误就return一个返回值,表示错误,这里,我建议大家不要直接返回true或者false,可以返回1,2,3,4...这样的数字,而且,每一种情况的返回值不同,这样在调试的时候能够很快找到是哪里错了。
#include<iostream>
#include<stdio.h>
using namespace std;
bool P[5][7];
void init()
{
int i,j;
for(i=0;i<5;i++)
{
for(j=0;j<7;j++)
{
P[i][j]=1;
}
}
P[1][6]=0;
P[3][6]=0;
P[4][3]=P[4][6]=0;
}
int judge()
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<7;j++)
{
if(P[i][j%7]==1&&P[i][(j+1)%7]==1&&P[i][(j+2)%7]==1&&P[i][(j+3)%7]==1)
return 1;
}
}
int count=0;
bool flag=true;
for(j=0;j<7;j++)
{
for(i=0;i<5;i++)
{
if(P[i][j]==0)
{
flag=false;
}
}
if(flag)
count++;
flag=true;
}
if(count<3)
return 2;
count=0;
for(j=0;j<7;j++)
{
for(i=0;i<4;i++)
{
if(P[i][j]==1)
count++;
}
if(count<2)
return 3;
count=0;
}
if(P[0][2]==0)
return false;
count=0;
for(j=0;j<7;j++)
{
if(P[0][j]==1&&P[2][j]==1)
count++;
}
if(count<4)
return 4;
return 5;
}
void show()
{
int i,j;
for(i=0;i<5;i++)
{
for(j=0;j<7;j++)
{
cout<<P[i][j]<<' ';
}
cout<<endl;
}
}
void getD()
{
int i;
for(i=0;i<6;i++)
{
P[3][i]=0;
if(judge()==5)
{
show();
cout<<endl;
}
P[3][i]=1;
}
}
void getC()
{
int i,j;
for(i=0;i<7;i++)
{
for(j=i+1;j<7;j++)
{
P[2][i]=P[2][j]=0;
getD();
P[2][i]=P[2][j]=1;
}
}
}
void getB()
{
int i;
for(i=0;i<6;i++)
{
P[1][i]=0;
getC();
P[1][i]=1;
}
}
void getA()
{
int i,j;
for(i=0;i<7;i++)
{
for(j=i+1;j<7;j++)
{
P[0][i]=P[0][j]=0;
getB();
P[0][i]=P[0][j]=1;
}
}
}
int main()
{
init();
getA();
return 0;
}
相关文章推荐
- 蓝桥杯 第39级台阶 (dfs and 回溯)
- 蓝桥杯 兰顿蚂蚁(dfs&&模拟)
- 2015蓝桥杯 三羊献瑞(回溯法dfs)
- (算法)DFS深度优先搜索—2016年蓝桥杯省赛java剪邮票
- 蓝桥杯 剪邮票(暴搜dfs)
- 蓝桥杯--2011--购物券(dfs)
- 蓝桥杯 算法提高3000米排名预测(全排列,dfs,bfs)
- 蓝桥杯 PREV-33 兰顿蚂蚁 (dfs)
- 蓝桥杯 7对数字 (dfs)
- 2016 第七届 蓝桥杯第7题 剪邮票(bfs+dfs)
- 【蓝桥杯-dfs】走迷宫路数
- 2013年第四届蓝桥杯C/C++省赛 第39级台阶(结果填空) ----DFS深度搜索遍历和暴力搜索
- 蓝桥杯 历届试题 剪格子 简单的DFS~~注意输入有陷阱~~
- 蓝桥杯第六届 牌型种数(dfs)
- 蓝桥杯 填符号凑算式 趣味运算 DFS枚举 字符串处理
- 2017第八届蓝桥杯省赛-大学A组 方格分割(深搜dfs)
- 【DFS回溯】(2015)第六届蓝桥杯省赛 C/C++ A组 题解(第五题)
- 蓝桥杯—李白打酒 dfs
- 第四届蓝桥杯C++B组——第39级台阶(dfs)
- 蓝桥杯 兰顿蚂蚁(dfs&&模拟)