穷举——排日期

某保密单位机要人员 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行记录,从星期一开始。

【输入、输出格式要求】

程序没有输入,要求输出所有可能的方案。

每个方案是5*7的矩阵。只有1和0组成。        

矩阵中的列表示星期几,从星期一开始。

矩阵的行分别表示A,B,C,D,E的作息时间表。

多个矩阵间用空行分隔开。

例如,如下的矩阵就是一个合格的解。请编程输出所有解(多个解的前后顺序不重要)。

0110111
1101110
0110111
1101110
1110110


public class Main {

    public static int[][] table = {
        {0,0,1,0,0,0,1},
        {0,0,0,0,0,0,0},
        {0,0,0,0,0,0,1},
        {0,0,0,0,0,0,0},
        {1,1,1,0,1,1,0}
    };

    //每周需要工作5天,休息2天。
    public static boolean fun0(){
        for(int i=0;i<5;i++){
            int cnt = 0;
            for(int j=0;j<7;j++){
                if(table[i][j]==1) ++cnt;
            }
            if(cnt!=5) return false;
        }
        return true;
    }

    //1. 所有人的连续工作日不能多于3天(注意:周日连到下周一也是连续)。
    public static boolean isLonger(int i){//统计第i个人的工作情况
        for(int j=0;j<7;j++){
            int cnt = 0;
            for(int k=0;k<4;k++){
                int v = (j+k)%7;
                if(table[i][v]==1){
                    ++cnt;
                }
            }
            if(cnt==4) return true;
        }
        return false;
    }
    public static boolean fun1(){
        for(int i=0;i<5;i++){
            if(isLonger(i)) return false;
        }
        return true;
    }

    //2. 一周中,至少有3天所有人都是上班的。
    public static boolean isFull(int j){//判断第j天是否所有人都上班
        for(int i=0;i<5;i++){
            if(table[i][j]!=1) return false;
        }
        return true;
    }
    public static boolean fun2(){
        int cnt = 0;
        for(int j=0;j<7;j++){
            if (isFull(j)) ++cnt;
        }
        if(cnt>=3) return true;
        return false;
    }

    //3. 任何一天,必须保证 A B C D 中至少有2人上班。
    public static boolean isABCD(int j){//判定在第j天是否A B C D 中至少有2人上班。
        int cnt = 0;
        for(int i=0;i<4;i++){
            if(table[i][j]==1) cnt++;
        }
        if(cnt>=2) return true;
        return false;
    }
    public static boolean fun3() {
        for(int j=0;j<7;j++){
            if(!isABCD(j)) return false;
        }
        return true;
    }

    //4. B D E 在周日那天必须休息。
    public static boolean fun4() {
        if(table[1][6]==0&&table[3][6]==0&&table[4][6]==0) return true;
        return false;
    }

    // 5. A E 周三必须上班。
    public static boolean fun5() {
        if(table[0][2]==1&&table[4][2]==1) return true;
        return false;
    }
   // 6. A C 一周中必须至少有4天能见面(即同时上班)。

    public static boolean fun6() {
        int cnt = 0;
        for(int j=0;j<7;j++){
            if(table[0][j]==1&&table[2][j]==1) ++cnt;
        }
        if(cnt>=4) return true;
        return false;
    }

    public static void show(){
        //System.out.println("Output table:");
        for(int i=0;i<5;i++){
            for(int j=0;j<7;j++) System.out.print(table[i][j]);
            System.out.println();
        }
        System.out.println();
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        //要把表全部构建起来才能进行判定,现在关键在于如何罗列出表的所有情况
        //按从层次进行分解,穷举
        for(table[0][0]=0;table[0][0]<2;table[0][0]++)
        for(table[0][1]=0;table[0][1]<2;table[0][1]++)  
        for(table[0][2]=0;table[0][2]<2;table[0][2]++)
        for(table[0][3]=0;table[0][3]<2;table[0][3]++)
        for(table[0][4]=0;table[0][4]<2;table[0][4]++)  
        for(table[0][5]=0;table[0][5]<2;table[0][5]++)
        for(table[0][6]=0;table[0][6]<2;table[0][6]++)

        for(table[1][0]=0;table[1][0]<2;table[1][0]++)
        for(table[1][1]=0;table[1][1]<2;table[1][1]++)  
        for(table[1][2]=0;table[1][2]<2;table[1][2]++)
        for(table[1][3]=0;table[1][3]<2;table[1][3]++)
        for(table[1][4]=0;table[1][4]<2;table[1][4]++)  
        for(table[1][5]=0;table[1][5]<2;table[1][5]++)
        for(table[1][6]=0;table[1][6]<2;table[1][6]++)  

        for(table[2][0]=0;table[2][0]<2;table[2][0]++)
        for(table[2][1]=0;table[2][1]<2;table[2][1]++)  
        for(table[2][2]=0;table[2][2]<2;table[2][2]++)
        for(table[2][3]=0;table[2][3]<2;table[2][3]++)
        for(table[2][4]=0;table[2][4]<2;table[2][4]++)  
        for(table[2][5]=0;table[2][5]<2;table[2][5]++)
        for(table[2][6]=0;table[2][6]<2;table[2][6]++)  

        for(table[3][0]=0;table[3][0]<2;table[3][0]++)
        for(table[3][1]=0;table[3][1]<2;table[3][1]++)  
        for(table[3][2]=0;table[3][2]<2;table[3][2]++)
        for(table[3][3]=0;table[3][3]<2;table[3][3]++)
        for(table[3][4]=0;table[3][4]<2;table[3][4]++)  
        for(table[3][5]=0;table[3][5]<2;table[3][5]++)
        for(table[3][6]=0;table[3][6]<2;table[3][6]++)
        {
                     if(fun0()&&fun1()&&fun2()&&fun3()&&fun4()&&fun5()&&fun6()) show();
        }
    }

}

首先,拿到这道题时应先根据题意列出初始A,B , C , D , E 状态,然后再根据条件:所有人的连续工作日不能多于3天(注意:周日连到下周一也是连续)以及工作5天,休息两天,即可得E的工作表情况:1110110。
然后,需要对除E以为表中的每个单元进行穷举,以人为第一单位,以日期为第二单位(穷举时往往会由于,for循环语句过多而混乱,这样便于表达思路)。
最后,就是对题目中的条件的表达,从代码中可以看到,并不是把每个条件的所有实现都写在了一起,而是复杂的又进行了割裂,这样虽然多写了几行代码,但是一个一个模块的实现、组合,让思路更加的清晰,保证了程序的可读性,以及后续代码的稳定编写!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值