题目描述
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
思路
我想分享一下自己初次尝试的解法,方便大家理解。
我们可以创建一个二维关系矩阵nums,如果a跟b认识,则nums[a][b]=1,不认识,则nums[a][b]=0。创建一个rooms[i][j],其中i表示第i个房间,j表示这个房间的第j个人。刚开始我们将第一个人先放进房间,然后从第2个人开始遍历到第n个人,每次从第一个房间遍历,如果这个人和这个房间有人认识,那么往下遍历,如果每个房间都有认识的,那就再开个房间。
以下是我初次尝试的写法,只有40%通过率,我会分析我的错误原因。
n=int(input())#人数
nums=[[0 for i in range(n+1)] for j in range(n+1)]#存储每个人之间的关系(是否认识)
m=int(input())
while m:
a,b=map(int,input().split())
nums[a][b]=nums[b][a]=1#如果a和b认识,赋值为1
m-=1
rooms=[[1]]#先将第一个人开一个房间
for i in range(2,n+1):
flag=0#标记第i个人是否能进入现有的房间
for j in range(len(rooms)):遍历现有房间
sum=0#统计次数
for k in rooms[j]:
sum+=1
if nums[i][k]==1:#表示第i个人与这个房间里有认识的人
break
if sum==len(rooms[j]):#如果遍历完这个房间,都没认识的人,就把第i个人加入这个房间
rooms[j].append(i)
flag=1
break
if flag==1:
break
if flag==0:
rooms.append([i])
print(len(rooms))
测试样例是正确的,但只有40%的通过率。原因在于假设现在有6个人,已经有5个人分为考场了
rooms=[[1],[2,3],[4,5]
现在6过来了,6跟1,3,4都认识,2跟第三个考场中4,5不认识,按照我的算法,将会为6开辟一个考场,实际上可以让2去第三个考场,6进第二个考场。
以下为正确做法
import os
import sys
# 输入节点个数n
n=int(input())
# 输入边的个数m
m=int(input())
# 创建一个n+1行n+1列的二维数组nums,用来存储图的邻接矩阵,nums[i][j]表示节点i和节点j之间是否有边相连,0表示没有,1表示有
nums=[[0]*(n+1) for i in range(n+1)]
# 创建一个n+1行n+1列的二维数组rooms,用来存储每个房间里放了哪些节点,rooms[i][j]表示第i个房间里的第j个节点,0表示空
rooms=[[0]*(n+1) for i in range(n+1)]
# 创建一个变量ans,用来记录最少需要的房间数,初始值设为一个很大的数
ans=1000000
# 循环m次,输入每条边的两个端点a和b,并更新nums数组
for i in range(m):
a,b=map(int,input().split())
nums[a][b]=1
nums[b][a]=1
# 定义一个深度优先搜索函数DFS,参数x表示当前要放置的节点,cnt表示已经使用的房间数
def DFS(x,cnt):
# 声明ans为全局变量,方便在函数内部修改
global ans
# 如果已经使用的房间数大于等于当前的最优解,就剪枝返回,不再搜索
if cnt>=ans:
return
# 如果当前要放置的节点超过了n,说明所有节点都已经放置完毕,就更新最优解并返回
if x>n:
ans=min(cnt,ans)
return
# 循环从1到cnt+1,尝试把当前节点放在每个已经使用过或者新开的房间里
for i in range(1,cnt+1):
# 初始化一个变量k为0,用来记录当前房间里有多少个节点
k=0
# 循环判断当前房间里的每个节点是否和当前要放置的节点有边相连,如果没有就继续往后找,如果有就跳出循环
while rooms[i][k]!=0 and nums[x][rooms[i][k]]==0:
k+=1
# 如果找到了当前房间里的一个空位,并且和当前要放置的节点没有边相连,就把当前节点放在这个空位上,并递归搜索下一个节点,然后把这个空位还原为0,并跳出循环(因为不需要再尝试其他房间了)
if rooms[i][k]==0:
rooms[i][k]=x
DFS(x+1,cnt)
rooms[i][k]=0
break
# 如果上面的循环没有找到合适的房间,就新开一个房间,并把当前节点放在这个房间里的第一个位置,并递归搜索下一个节点,然后把这个位置还原为0(因为可能有更优的方案)
rooms[cnt+1][0]=x
DFS(x+1,cnt+1)
rooms[cnt+1][0]=0
# 调用DFS函数从第一个节点开始搜索,并传入初始房间数为0
DFS(1,0)
# 输出最优解ans
print(ans)
# 请在此输入您的代码