蓝桥杯历届试题分考场-回溯搜索最值

问题描述
  n个人参加某项特殊考试。
  为了公平,要求任何两个认识的人不能分在同一个考场。
  求是少需要分几个考场才能满足条件。
输入格式
  第一行,一个整数n
(1<n<100),表示参加考试的人数。
  第二行,一个整数m,表示接下来有m行数据
  以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
输出格式
  一行一个整数,表示最少分几个考场。
样例输入
5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
样例输出
4
样例输入
5
10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
样例输出
5




#include<iostream>
#include<vector>
using namespace std;
#define MAXN 110
#define INF 0x3f3f3f3f;
int graph[MAXN][MAXN];//建立图
int cun[MAXN][MAXN];//存储第几个教师有谁谁谁
int cnt[MAXN]={0};//记录每个教室的人数
int res=INF;//假设需要一个无穷多的教室
int n,m;//定义人数,以及认识的数目
void solve(int id,int num)//回溯搜索,id表示当前安排的是第id的同学,num表示当前安排这个id同学的时时候已经用了多少个教室
{
        if(num>=res)//如果当前的教室方案已经超过以前的方案了,那么就放弃返回
        return;
    if(id>n)//如果说id的同学的id>n说明全部的同学都安排完了
        {
        res=num;//如果执行到这一步说明res一定是.>num的,所以更新一下
        return;//返回
        }
    for(int i=0;i<num;i++)//扫描每一个已经存在的教室
    {
        int len=cnt[i];//取一下当前i教室的人数
        int c=0;//这个变量表示当前id的同学和这个教室的同学不认识的人数
        for(int j=0;j<len;j++)//扫描这个教室的每一个同学
        {
            if(graph[id][cun[i][j]]==0)//如果没有关系
                c++;//加1
        }
        if(c==len)//如果全部不认识
        {
            cun[i][cnt[i]++]=id;//那么id同学就进入这个教室,同时这个教室的人数+1
            solve(id+1,num);//那么安排下一个教室
            cnt[i]--;//递归返回之后把这个同学在从这个教室分走,分到下几个教室看看
        }
    }
    cun[num][cnt[num]++]=id;//如果全部教室都存在id认识的同学,那么就把这个同学新开个教室
    solve(id+1,num+1);//递归下一个同学并且当前的教室数目+!
    cnt[num]--;//返回后移除这个同学看下上一个同学有没有其他的选择
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        graph[a][b]=1;
        graph[b][a]=1;//如果两个人认识的话就可以标记成1,c++在数组创建 的时候已经快速初始化
    }
    solve(1,0);//进入回溯更新最小的教室数目
    cout<<res;//输入所有可能中的最小的答案
}

猜你喜欢

转载自blog.csdn.net/memeda1141/article/details/80301201