蓝桥杯决赛之排日程



【编程题】(满分32分)


    某保密单位机要人员 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


分析:本题就是简单的暴搜加剪枝,每个人一周内每天有工作和休息两种情况,对于5*7的矩阵,从上到下,从左到右遍历递归,每遇到当前已经确定的作息表能进行判断的情况,就进行判断,比如,某行的数据确定,即改行代表的某人一周的作息表确定,那么据此可以进行第一个条件和最基本的条件(每周需要工作5天,休息2天),如果满足,那么继续下一行的搜索,不满足,那么这条路就结束,开始下一条路,这样就起到了剪枝的效果.源码如下:
#include<cstdlib>
#include<cstdio>
#include<iostream>
using namespace std;
int arr[5][7];
//int arr[5][7]={{0,0,1,0,1,1,1},{1,1,0,1,1,1,0},{0,1,1,0,1,1,1},{1,1,0,1,1,1,0},{1,1,1,0,1,1,0}};
int index=1;
void print()
{
	printf("%d-------------\n",index++);
	
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<7;j++)
    	   printf("%d",arr[i][j]);
    	printf("\n");
	}
	
}
bool check()
{
	
	int quan=0;                      //第二个条件,一周中,至少有3天所有人都是上班的。 
	for(int c=0;c<7;c++)
	{
		bool quanshang=true;
	    for(int i=0;i<5;i++)
	    {
	    	if(arr[i][c]==0) 
	    	{
	    		quanshang=false;
	    		break;
	    	}
	    }
	    
	    if(quanshang==true) quan++;
	}
	if(quan<3) return false;
	
	for(int c=0;c<7;c++)   //第三个条件,任何一天,必须保证 A B C D 中至少有2人上班。 
	{
		if(arr[0][c]+arr[1][c]+arr[2][c]+arr[3][c]<2) return false;
	}
	
	int ac=0;        //第六个条件,A C 一周中必须至少有4天能见面(即同时上班) 
	for(int c=0;c<7;c++) 
	{
		if(arr[0][c]==1 && arr[2][c]==1) ac++;
	}
	if(ac<4) return false;
	
	return true;
}
bool checkhang(int hang)
{
		int gong=0;
		for(int c=0;c<7;c++)
		{
			if(arr[hang][c]==1) gong++;
		}
		if(gong!=5) return false;
	
		for(int start=0;start<=6;start++)
		{
			if(arr[hang][start]+arr[hang][(start+1)%7]+arr[hang][(start+2)%7]+arr[hang][(start+3)%7]>=4)
			  return false;
		}
	
	return true;
}
void dfs(int x,int y)
{

    if(y==0 && x!=0)         //例如当遍历到arr[3][0]说明第三行arr[2][0]~arr[2][6]已经确定,那么进行行判断 
    {
       if(!checkhang(x-1)) return;	
    }

    if(x==5 && y==0)        //遍历到最后一个元素arr[4][6]的下一个元素 
    {
	   	if(check())
	   	   print();
	   	return;
    }
    
    
    int nextx=x;
    int nexty=y+1;
    if(nexty>6)         //一行结束 
	{
	   nextx++;//已经到行尾,则下一行 
	   nexty=0;
	}    
	if(y==6 && (x==1 || x==3 || x==4) )
	{
		arr[x][y]=0;
        dfs(nextx,nexty);
	}
    else if(y==2 && (x==0 || x==4))
    {
    	arr[x][y]=1;
        dfs(nextx,nexty);
    }
    else
    {
    	arr[x][y]=0;
        dfs(nextx,nexty);
        arr[x][y]=1;
        dfs(nextx,nexty);
    }
    
    
}
int main()
{
	dfs(0,0);
	return 0;
} 


PS:每个月至少四篇博客,要加油~


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值