蓝桥杯之分考场-深度优先遍历(DFS)+简单逻辑判断简化版(c++实现)

上文链接:蓝桥杯之小型计算器-分治法思想+简单逻辑判断(c++实现)


资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

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

规划+暴力简化版

我的思路

  • 整体思想是:所有在刚开始都在第一个房间,然后按照认识人之间的关系从第一个房间到当前分配的最后一个房间进行查找,查找到则将人a(a从1到n)认识的人移出到下个房间,为查找到继续查找,直到查完所有房间结束(结束时该人就默认放到第一个房间)。。。
  • 注意点1: 将认识人关系表按照a>b的关系录入(有助于简化运算,代码已注释,看代码可知)
  • 注意点2:将所有人都默认放到第一个房间,所有人从小到大删选出当前房间。筛选过程:按照关系表里关系,将在当前房间查找到对应关系的人a(a为编号)认识的人b转移到下一个房间,若未查找到人b则在下一个房间继续查找。。。直到查找到当前安排的最后一个房间结束。
  • 我的这个过程有两个问题:
    1. 默认规定好了查不到的人放在第一个房间.
    2. a认识的人b只能存放到a的下一个房间。

算法展示

#include <iostream>
using namespace std;
int main()
{
	int n,m;
	int a_b[100][2],r;//题中所示a_b[]为认识人数组.r为房间数 
	int room[100][101];//[0][0-100]默认为1,即所有人都在[0]房间中, 
	cin>>n>>m;
	for(int i=0;i<=n;i++)//初始化room房间数组 
	{	
		room[0][i]=1;	
	}
	
	//输入认识人数组 
	for(int i=0;i<m;i++)
	{	
		cin>>a_b[i][0]>>a_b[i][1];
		
		//0位置存储较小值,1位置存储较大值 
		if(a_b[i][0]>a_b[i][1])
		{
			int temp = a_b[i][0];
			a_b[i][0] = a_b[i][1];
			a_b[i][1] = temp; 
		}
	}
	
	for(int j=1;j<=n;j++)//人按序号从小到大 
	{
		for(int i=0;i<m;i++)//认识人列表从前往后 
		{
			if(a_b[i][0]==j)//判断每一对认识人数组中是否是当前最小序号人 
			{
				for(r=0;r<n;r++)//将当前房间中最小序号人认识的人转移到下个房间 
				{
					/*从第一个房间到当前存在的最后一个房间判断a_b[i][0],a_b[i][1]
					是不是在同一个房间,是则将两者中较大值a_b[i][1]向下一个房间
					转移 
					*/ 
					if(room[r][a_b[i][0]]==1&&room[r][a_b[i][1]]==1)
					{
						room[r+1][a_b[i][1]]=1;
						room[r][a_b[i][1]]=0;
						break;
					}				
				}
			}
		} 
	}
	
	
	int count=0;
	r=0;
	while(count!=n)
	{
		for(int j=1;j<=n;j++)
		{
			if(count==n)break;
			if(room[r][j]==1)++count; 
		}
		r++;
	}
	
	cout<<r<<endl; 
	return 0;	
}

我写的算法存在问题,所以我参考了网上自己整理了思路又写了一遍递归版(解决了上述我的问题)

递归简化版

我的思路

  • 从第一个人a(a到0到n)开始安排,在当前所有存在的房间查找认识的人。查找到则安排到某房间(该房间不定,因为所有的房间都要尝试一遍,因此采用深度优先遍历思想,查找到某房间符合并安排人a后及时回溯到安排的状态进行下个房间的查找),安排后则安排下个人;没有查找到则查找下个房间。。。
  • 注意事项:该方法仍然可以改进,仅因为此种写法最节省时间(因为我写了几遍并参考网上现有资源,所写的这个代码量最少),因此我展示出来。

算法展示

#include <iostream>
using namespace std;
int n,m;//考试人数n,m行数据 
int a_b[500][2];//认识人关系表
int rooms[100][101]={0};//房间数 
int r_max = 100;

void find_max(int p,int room_s)//当前安排人p,当前安排房间最大值room_s 
{
	if(r_max<=room_s)//如果现在安排房间room_s比众多安排房间方案中最小房间r_max大,则结束递归 
	{
		return; 
	} 
	if(p>n)//如果多于考试人数则结束递归
	{
		r_max = room_s;
		return;
	}
	int flag=1; 
	for(int j=0;j<room_s;j++)//从第一个考试房间查找到当前已经分配的最大值房间
	{
		for(int i = 0;i<m;i++)//查找m个认识人关系表 
		{
			/*查找认识人关系表中和p认识的人,若该人存在则判断该人是否已经存在此房间,在的话将flag置为零,表示此房间不能安排人p。 */
			if(a_b[i][0]==p&&(rooms[j][a_b[i][1]]==1))
			{
				flag=0;
			}
			if(a_b[i][1]==p&&(rooms[j][a_b[i][0]]==1))
			{
				flag=0;
			}
		}
		if(flag)//该房间没有查找到和p认识的人则flag=1,可以将p放到该房间。 
		{
			rooms[j][p]=1;
			find_max(p+1,room_s);
			rooms[j][p]=0;
		}
		flag=1;//每进一个房间就要把flag初始为1,表示该房间没有认识的人 
	}
	//上述过程房间不满足存放人p,则新开房间安排人p 
	rooms[room_s][p]=1;
	find_max(p+1,room_s+1);
	rooms[room_s][p]=0;
}

int main()
{
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		cin>>a_b[i][0]>>a_b[i][1];
	}
	find_max(1,1);
	
	cout<<r_max<<endl;
	return 0;	
}

下文链接:蓝桥杯之小数第n位-数组存储+直接计算版(c++实现)

发布了30 篇原创文章 · 获赞 3 · 访问量 2759

猜你喜欢

转载自blog.csdn.net/weixin_44077556/article/details/104318372