DFS每日一练

前言

这次这道题比较复杂,不仅中途要存储数据而且还需要建设map映射关系。思路详情见代码。

题目

小明成为了是一个活动的总负责人。当前活动有N名活跃会员,每月会进行K次活动。
小明准备了纪念品,想在下个月进行活动时,送给会员们。
小明为了给更多的会员送礼物,她调查了下个月进行活动时,每个会员能参与的K个日期。

请使用调查结果根据如下的条件编写可确定K个活动日程的程序。

  1. K 个活动中,只要参与1次就可以收到纪念品。
  2. 小明进行活动时,想让更多的人拿走纪念品。
  3. 日程中,拿走纪念品的人数相同的话,第一次活动日程选择更早的日程。
  4. 拿走纪念品的人数相同,第一次的活动日程也相同的话,第二次活动日程选择更早的日程。(第二次活动日程相同的话,第三次…)

[限制事项]

  1. 会员数N是1以上100以下的自然数。
  2. 活动的次数K是1以上5以下的自然数。
  3. 下个月日期是1日到30日之间。
  4. 一名会员提交的K个可参与日期是不重复的。
  5. 所有会员不能参与的日期也包含在活动日程上。

[输入]
首先给出测试用例个数T,从下一行开始给出T个测试用例。
各测试用例的第一行空格区分给出同好会会员数N和下个月要进行的活动次数K。
然后再通过N行,每行空格区分给出各会员可参与的K个日期。

[输出]
对各个测试用例输出#x(x是测试用例号码,从1开始),隔一个空格后,输出当进行K次活动时,能收到纪念品的会员数和升序排列的K个活动日程的日期。

[输入输出 案例]
(输入)
2
7 2
16 19
1 4
1 8
4 8
16 9
16 4
4 16
9 3
17 19 6
2 19 6
17 21 2
4 20 19
19 4 6
4 2 17
4 21 17
17 19 4
20 21 6

(输出)
#1 6 1 16
#2 9 2 4 6


思路

  1. 活动日去重和排序:将网格中出现的所有活动日提取出来,存入一个列表dayList中,并对这个列表进行排序。排序的目的是为了后续在DFS过程中能够按顺序尝试选择活动日,从而方便比较字典序。

  2. 构建映射关系:使用一个HashMap map来存储每个活动日到参加该活动的人的索引列表的映射关系。这是通过遍历网格和dayList来实现的,对于dayList中的每个活动日,找到网格中所有选择该活动日的人,并将他们的索引添加到对应的列表中。

  3. DFS:初始化最大参加人数answer为0,以及用于存储选择的活动日的数组selectedDays、临时数组tempDays和标记人是否被访问过的布尔数组visited。然后调用DFS方法,从活动日列表dayList的第一个活动日开始尝试选择K个活动日。在DFS过程中,通过递归选择下一个活动日,并更新参加人数和已访问状态。

  4. 更新结果:在DFS的每一层递归中,如果已经选择了K个活动日,就检查当前的参加人数是否大于answer。如果是,则更新answer和selectedDays;如果相等,则比较当前选择的活动日数组和selectedDays的字典序,如果更小则更新selectedDays。

代码如下(示例):

import java.util.*;
public class huodongricheng {
   
	static int T, N, K, maxMembers;//同好会会员数N和下个月要进行的活动次数K,能收到纪念品的最大会员数maxmember
	static int [][]memberDates;//N行K列,元素为每个会员可参与的日期
	static List<Integer> dayList;//K个活动日程的最优活动日期组合
	static int[]selectDays;//存储选择的活动日
	static Map<Integer, List<Integer>> map;//定义一个映射存放会员与日期的关系
	static boolean[] visited;
	
	public static void main(String[] args) throws Exception{
   
		Scanner sc = new Scanner(System.in);
		T = sc.nextInt();
		for(int test_case = 1; test_case <= T; test_case++) {
   
			N = sc.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值