试题 历届真题 排日程表【第三届】【决赛】【高职组】
题解
好没把握。我好难过
自己一开始的思路是很有很有问题的。一开始是设置一个5*7的矩阵,每个位置穷举0 1,这样就有235 = 34,359,738,368 种可能。铁定算不出来。
然后自己后来又想到状态压缩,可是还是需要穷举,自己也还是不会了
归根结底在于自己想不出来好的方法穷举。
怪自己 动手能力太差,生活经验缺少,联系实际的能力很差。
对于a[i][j]表示i在周j上班:则a[i][j]只有两天休息,其他5天上班。
所以要做的是穷举休息日,两天即可。咋枚举?你根本不会
先枚举第一天 ,然后第二天要在第一天后面否则就会有重复。
但是这里需要初始化每个a[i][j]都为1 这样再去穷举那两个是0。
for(int i=1;i<=7;i++) 枚举休息日第一天
{
for(int j=i+1;j<=7;j++) 枚举休息日第二天
a[who][i] = 0;
a[who][j] = 0;
dfs(who);
a[who][i] = 1;
a[who][j] = 1;
6个条件 讲道理 我也有的不会。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10;
int a[N][N]; //a[i][j]表示i在周j工作
bool f1() //所有人连续工作日不能多于3天
{
//因为所有人的连续工作日不能超过3天,那就穷举四天 如果有干四天的情况 返回假,
for(int i=1;i<=5;i++)
for(int j=1;j<=7;j++)
{
int t1,t2,t3;
t1 = (j+1)%7;
t2 = (j+2)%7;
t3 = (j+3)%7;
if(t1==0) t1=7; // 注意整除的情况 如果整除说明正好在周日 但是取余的结果是0
if(t2==0) t2=7;
if(t3==0) t3=7;
if(a[i][j] + a[i][t1]+a[i][t2]+a[i][t3]==4) // 如果有干4天的情况
return false;
}
return true;
}
bool f2()
{
int sum = 0;
int res = 0;
for(int j=1;j<=7;j++)
{
sum = 0;
for(int i=1;i<=5;i++)
{
sum += a[i][j];
}
if(sum == 5 ) res ++; //工作5天不是7天!
}
return res >= 3 ;
}
bool f3()
{
for(int i=1;i<=7;i++)
{
if(a[1][i] + a[2][i] + a[3][i] + a[4][i] < 2)
return false;
}
return true;
}
bool f4()
{
if(a[2][7]==0 && a[4][7]==0 && a[5][7] == 0) return true;
return false;
}
bool f5()
{
if(a[1][3] + a[5][3]==2) return true;
return false;
}
bool f6()
{
int res = 0;
for(int i=1;i<=7;i++)
{
if(a[1][i] + a[3][i] == 2) res++;
}
return res >=4;
}
void dfs(int who)
{
if(who == 6) //出口
{
if(f1() && f2() && f3() && f4() && f5() && f6())
{
for(int i=1;i<=5;i++)
{
for(int j=1;j<=7;j++)
printf("%d",a[i][j]);
puts("");
}
puts("");
}
return;
}
//枚举休息日 连续的两天
for(int i=1;i<=7;i++)
{
for(int j=i+1;j<=7;j++)
{
a[who][i] = 0;
a[who][j] = 0;
dfs(who+1);
a[who][i] = 1;
a[who][j] = 1;
}
}
}
int main()
{
//全部初始化为1 然后枚举找休息日
for(int i=1;i<=6;i++)
for(int j=1;j<=7;j++)
a[i][j] = 1;
dfs(1);
}