问题描述:
某保密单位机要人员 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
【注意】
请仔细调试!您的程序只有能运行出正确结果的时候才有机会得分!
在评卷时使用的输入数据与试卷中给出的实例数据可能是不同的。
思路:用回溯法解决。数的深度为35,,解空间数为二叉树,1-7层表示A周一至周日的上班情况,8-14表示B周一至周日的上班情况,由此类推。
代码:
package lanqiao;
import java.util.ArrayList;
import java.util.List;
public class PaiRiCheng {
/**
* @param args
*/
public static void main(String[] args) {
new PaiRiCheng().print();
}
public void print(){
back(0);
for(int i=0;i<solutions.size();++i){
int []solution=solutions.get(i);
for(int j=0;j<solution.length;++j){
System.out.print(solution[j]);
if((j+1)%7==0){
System.out.println();
}
}
System.out.println();
}
}
//保存从根节点到当前结点的路径
//paht[0]至path[6]表示A的上班情况,path[7]至path[13]表示B的上班情况,由此类推。
private int[] path = new int[35];
//保存所有的解
private List<int[]> solutions = new ArrayList<int[]>();
public void back(int n) {
if (n < 35) {
for (int i = 0; i < 2; ++i) {
path[n] = i;
if (constraint(n)) {
if (n == 34) {
if (isTarget()) {
solutions.add(clonePath());
}
} else {
back(n + 1);
}
}
}
}
}
public int[] clonePath() {
int[] solution = new int[35];
for (int i = 0; i < solution.length; ++i) {
solution[i] = path[i];
}
return solution;
}
public boolean isTarget() {
//一周中,至少有3天所有人都是上班的
int total=0;
for(int i=0;i<7;++i){
int shangBanRenShu=0;
for(int j=0;j<5;++j){
if(path[i+7*j]==1){
shangBanRenShu++;
}
}
if(shangBanRenShu==5){
total++;
}
}
if(total<3){
return false;
}
return true;
}
public boolean constraint(int n) {
//每周需要工作五天
if((n+1)%7==0){
int total=0;
for(int i=n-6;i<n+1;++i){
if(path[i]==1){
total++;
}
}
if(total!=5){
return false;
}
}
//所有人的连续工作日不能多于3天
if((n+1)%7==0){
for(int i=n-6;i<n+1;++i){
int total=0;
for(int j=i;j<i+4;++j){
int k=j;
if(j>=n+1){
k=j-7;
}
if(path[k]==1){
total++;
}
}
if(total>=4){
return false;
}
}
}
//任何一天,必须保证ABCD中至少有两人上班
if(n==27){
for(int i=0;i<7;++i){
int total=0;
for(int j=0;j<4;++j){
if(path[i+j*7]==1){
total++;
}
}
if(total<2){
return false;
}
}
}
// BDE在周日那天必须休息
if ((n == 13 || n == 27 || n == 34) && path[n] == 1) {
return false;
}
//AE周三必须上班
if((n==2||n==30)&&path[n]==0){
return false;
}
//AC一周中至少四天同时上班
if(n==20){
int total=0;
for(int i=0;i<7;++i){
if(path[i]==1&&path[14+i]==1){
total++;
}
}
if(total<4){
return false;
}
}
return true;
}
}