分考场

问题描述
  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

代码:

import java.util.*;
public class Main {
    //判断两人是否认识
  static boolean flag[][];
  static int n,ans;
  //存放教室
  static List<List<Integer>>list=new LinkedList<List<Integer>>();
  public static void main(String[] args) {
    Scanner scanner=new Scanner(System.in);
    //人数
    n=scanner.nextInt();
    //组数
    int m=scanner.nextInt();
    //00代表初始的喔,下标从1开始,故n+1
    flag=new boolean[n+1][n+1];
    for(int i=0;i<m;i++){
        int a=scanner.nextInt();
        int b=scanner.nextInt();
        flag[a][b]=flag[b][a]=true;
    }
    //分考场的总数
    ans=101;
    dfs(1);
    System.out.println(ans);
}
  
  /**
   * 通过flag判断当前的now是否与当前教室中的人认识,是否可以放到当前的list中去
   * @param index  教室的编号
   * @param now    当前要加入交是的同学编号
   * @return
   */

  static boolean check(int index,int now){
       //list.get(index).size()得到教室的人数
      for(int i=0;i<list.get(index).size();i++){
          //list.get(index).get(i)代表该教室的第i个学生的编号
          if(flag[now][list.get(index).get(i)]){
              return false;
          }
      }
      return true;
  }
  
  public static void dfs(int now){
      if(now==n+1){//当前的学生编号大于总人数,则选优
          //选优,list.size()为当前教室的总数

          ans=Math.min(ans,list.size());
          return;
      }
      //当你这个状态的递归得到的教室数目已经大于已知状态的教室数目,则退出
      if(list.size()>=ans) return;
      //依次的遍历第i个教室的学生,查看是否认识now
      for(int i=0;i<list.size();i++){
          if(check(i, now)){//不认识now
              //把当前学生加入该教室

              list.get(i).add(now);
              //递归下一个学生
              dfs(now+1);
              //回溯,删除刚刚加进去的那个人
              list.get(i).remove(list.get(i).size()-1);
          }
      }
      
      //以下当now都被所有所有教室的学生认识或者就算不认识也不加入已知的教室,则新建一个教室存放now
      //创建临时的list,即教室

      List<Integer>temp=new LinkedList<>();
      //该教室加入当前的那个学生
      temp.add(now);
      //登记该教室
      list.add(temp);
      //递归这种情况
      dfs(now+1);
      //回溯,将刚才加入的教室删除,表示这种状态递归搜索完成,初始化list以备下次递归
      list.remove(list.size()-1);  
  }

}

参考博客:

https://blog.csdn.net/habewow/article/details/80410177

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值