蓝桥杯分考场
程序员文章站
2022-05-20 22:33:40
...
因为数据量很小可以使用回溯算法。
应用两层回溯:
第一层回溯是将考生放在不同考场里面产生的效果,比如学生3号可以放在教室1和教室2中那么放在那一个教室会产生更好的效果这是一层回溯。
第二层回溯是考生放入以前的考场还是考生自己重新用一个考场。比如考生3号可以放进教室1和教室2,也可以放进教室3。
应用简单的剪枝技巧:
现在考场的数量已经大于以前最少的考场数量了就不用在展开了。
因为题目中没有时间限制,所以可以不使用vector,使用二维数组存放边,使用二维数组存放教室中学生。
另外使用vecot中的find()总是报错所以就不使用了
使用二维数组的时间复杂度约为O(nn)因为没一个学生需要遍历之前的考场就需要遍历每个人一次1 + 2…+n - 1;
使用vector最好的情况是NlogN,这种情况对应只有一个考场,每个学生耗费logN的复杂度,NlogN,最坏的情况就会退成O(NN),对应着N个考场,每个之前的学生都需要遍历一次。
#include<stdio.h>
#include<iostream>
#include<vector>
#include<string.h>
using namespace std;
const int maxn = 100 + 5;
int room[maxn][maxn];//保存教室i中第j个学生的id
int gra[maxn][maxn];//存图
int m,n;
int res = maxn + 500;//保存答案
void solve(int id,int num)
{
//printf("%d %d\n",id,num);
if(num >= res){//剪枝
return ;
}
if(id > n){//学生的编号从1开始防止room[][] = 0不是没学生的标志
res = min(res,num);
return ;
}
for(int i = 1;i <= num;i++){//找到id是否有符合的教室
int k = 0,flag = 1;
while(room[i][k]){//查找学生教室中是否有认识的人
// printf("%d %d %d\n",id,room[i][k],gra[id][room[i][k]]);
if(gra[id][room[i][k]]){//教室里面有认识的人
//printf("冲突\n");
flag = 0;
break;
}
k++;//不要写在数组里面防止执行顺序的不对而出错
}
if(flag){ //回溯一定对应着判断
room[i][k] = id;
solve(id+1,num);
room[i][k] = 0; //第一层回溯
}
}
//重新开启一个教室
room[num+1][0] = id;
solve(id+1,num+1);
room[num+1][0] = 0;//第二层回溯
}
void init()
{
memset(room,0,sizeof(room));
}
int main()
{
init();
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
int a,b;
scanf("%d%d",&a,&b);
gra[a][b] = gra[b][a] = 1;
}
solve(1,0);
printf("%d\n",res);
return 0;
}
上一篇: 遗传算法求解TSP问题
下一篇: 入栈出栈顺序