[蓝桥杯]排日程

【编程题】(满分34分)


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



网上看到了许多的解法,都感到过于复杂了,试着用位操作的方法来做,效果不错,把源码贴出来分享下


#include<iostream>
#include<string>
using namespace std;


unsigned int m[5] = {118,118,118,118,118}; 


string change2str(unsigned int n){
unsigned int t=128;
string s="";
char ch;

for(int i=0; i<8; i++,t>>=1)
{
ch = (n&t)>0?'1':'0';
if(i>0)
s.append(1,ch);
}
return s;
}


void leftMoveBit( int index){
unsigned int t=128;

m[index]<<=1;

if((m[index]&t)>0) 
 {m[index] &=127;  m[index]|=1;}


return ;
}


int is1bitPos(int m,int pos){
unsigned int t = 128;
t>>=pos;


return (m&t)>0;
}


int count1bits(int m){
int count=0;
for(int i=1; i<=7; i++){
if(is1bitPos(m, i)) count++;
}
return count;
}


int panDuan(){
//1. 至少有3天所有人都是上班的
unsigned int n = m[0]&m[1]&m[2]&m[3]&m[4];
if(count1bits(n)<3) return 0;

//2.任何一天,必须保证ABCD中至少有2人上班
int count;
for(int day=1; day<=7; day++){
count=0; 
for(int i=0; i<4; i++)
  if(is1bitPos(m[i],day)) count++;
if(count<2) return 0;


//3. B,D,E在周日时必须休息
if(is1bitPos(m[1],7)||is1bitPos(m[3],7)||is1bitPos(m[4],7)) 
 return 0;
 
    //4. A,E必须周三上班
if(!is1bitPos(m[0],3) || !is1bitPos(m[4],3))
return 0; 

//5. A C 一周之中至少有四天能够见面
if(count1bits(m[0]&m[2])<4) return 0;

return 1; 
}


int main(){

for(int i=0; i<7; i++,leftMoveBit(0))
for(int j=0; j<7; j++, leftMoveBit(1))
for(int k=0; k<7; k++, leftMoveBit(2))
for(int l=0; l<7; l++,leftMoveBit(3))
for(int w=0; w<7; w++, leftMoveBit(4))
  if(panDuan()) 
   {
cout<<change2str(m[0])<<endl;
cout<<change2str(m[1])<<endl;
cout<<change2str(m[2])<<endl;
cout<<change2str(m[3])<<endl;
cout<<change2str(m[4])<<endl;
cout<<"-------------------------"<<endl;
}
       

return 0;
}


运行结果为:

1011011
1110110
1011011
1110110
1110110
-------------------------
0110111
1101110
0110111
1101110
1110110
-------------------------
1011101
1110110
1011101
1110110
1110110
-------------------------
0111011
1110110
0111011
1110110
1110110
-------------------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值