NOJ 2030 收购计划 (枚举+DFS 好题)

2024-03-20 14:18

本文主要是介绍NOJ 2030 收购计划 (枚举+DFS 好题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


收购计划

时间限制(普通/Java) : 2000 MS/ 6000 MS          运行内存限制 : 16384 KByte

总提交 : 286            测试通过 : 23

题目描述

IT巨子松老师经过数十年的奋斗,终于打败了所有竞争对手准备一统IT界。此时除了松老师的帝国之外还有N个残存的小公司,松老师打算收购其中的一些。这些公司有a1、a2…an个员工,收购之后松老师打算把员工分给总裁办的K个助理进行管理,为了防止内部矛盾,松老师希望每个助理分到的员工数量都相同。松老师想知道自己最多可以收购多少家公司,使得总的员工数可以平均分配呢?



输入

第一行为一个正整数T,表示有T组数据(T<=20)

每组数据第一行为两个正整数n,k,表示有n家公司(n<=40),以及助理的人数(k<=1000000)

接下来的一行是n个正整数,表示每家公司的员工人数(ai<=5000000)

  

输出

一个整数m表示最多可以收购多少家公司

样例输入

2

3 3

1 2 3

5 7

1 10 10 10 10

样例输出

3


题目链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2030

题目分析:乍一看有点像搜索神题sticks,其实是个单向深搜,01背包的思想,对于每个值取或者不取

说一下几个剪枝

1.若总和是k的倍数,直接输出n

2.若当前使用的加上没使用的比枚举值小,说明该情况无解

这样做跑了109ms


#include <cstdio>
#include <cstring>
using namespace std;
int a[45], n, k, ans;bool DFS(int i, int tot, int cnt)
{if(n - i + cnt < ans)return false;if(cnt == ans){if(tot % k == 0)return true;elsereturn false;}if(DFS(i + 1, tot + a[i], cnt + 1))return true;if(DFS(i + 1, tot, cnt))return true;return false;
}int main()
{int T;scanf("%d", &T);while(T--){bool flag = false;int sum = 0;scanf("%d %d", &n, &k);for(int i = 0; i < n; i++){scanf("%d", &a[i]);sum += a[i];}if(sum % k == 0){printf("%d\n", n);continue;}for(int i = n - 1; i >= 1; i--){ans = i;if(DFS(0, 0, 0)){printf("%d\n", ans);flag = true;break;}}if(!flag)printf("0\n");}
}


大神31ms的做法:

通过同余来搜索答案,记总和对k取余为mod,然后再在这里面找一组和对k的余数为mod,差值就是答案,对于所有的a[i]如果a[i]本身就是k的倍数就可以不用放在待搜索的序列里了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[45];
int n, k, nn, MOD, tmp;int cmp(int a, int b)
{return a > b;
}bool DFS(int s, int mod, int used)
{if((nn - s + 1 + used) < tmp)return false;if(used == tmp){if(mod == MOD)return true;else return false;}if(DFS(s + 1, (mod + a[s]) % k, used + 1))return true;if(DFS(s + 1, mod, used))return true;return false;
}int main()
{int T;scanf("%d", &T);while(T--){int get;MOD = 0;memset(a, 0, sizeof(a));scanf("%d %d", &n, &k);for(int i = 0; i < n; i++){scanf("%d", &get);a[i] = get % k;MOD = (MOD + a[i]) % k;}if(MOD == 0){printf("%d\n", n);continue;}sort(a, a + n, cmp);nn = n;bool flag = false;while(a[nn - 1] == 0) //这里也是一个剪枝nn--;for(int i = 1; i < nn; i++){tmp = i;if(DFS(0, 0, 0)){printf("%d\n", n - i);flag = true;break;}}if(!flag)printf("0\n");}
}




这篇关于NOJ 2030 收购计划 (枚举+DFS 好题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/829724

相关文章

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。  总线驱动程序本质上是同时处理总线枚

IOS Swift 从入门到精通:数组,集合,元组,对比,字典,枚举

目录 数组 集合 元组 Arrays vs sets vs tuples 字典  字典默认值 创建空集合 枚举 枚举关联值 枚举原始值 复杂类型:总结 数组 数组是存储为单个值的值的集合。例如,John、Paul、George 和 Ringo 是姓名,但数组可让您将它们分组为单个值,即 The Beatles。 在代码中我们这样写: let john

java基础知识枚举提取公共类

引用地址:今日头条 如何规范化Enum在项目中的使用? 2022-03-02 14:14·老顾聊技术 前言 在我们平时开发过程中,枚举的使用时必不可少的。 为什么要用枚举? 有穷序列的字段用int或tinyint不是挺好吗? 答案很简单:我们的程序写给人看的。 既然是写给人看,那么,可理解、易理解往往显得相当重要! 枚举一般有两部分,一个是枚举项值,一个是枚举描述。那么,这两个

poj 1564 Sum It Up -- DFS 递归

题意:给一个数 t ,以及 n 个数,求 n 个数中的几个数加起来的和为 t 的情况有多少种。 注意:题目要求相同的组合方式不能出现2次,即 “3 4 1 1 1 1 ” 的结果为:“1+1+1”。 思路:一个  for  循环遍历一遍,每个 i 表示以当前数为起点开始一次DFS递归,当所遍历的和为 t 时,输出该组合方式,如果大于 t 则返回,小于则往下递归。以二维数组保存已经输出过的数据,

博弈论+递推+调和级数枚举,CF 1033C - Permutation Game

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1033C - Permutation Game 二、解题报告 1、思路分析 我们考虑一个位置符合什么条件可以必胜? 如果可以跳到一个必败的位置 考虑最大的格子一定是必败 而每个格子只能跳到比自己大的格子 于是我们就可以倒序处理状态 对于每个格子枚举比自己大

Android性能优化—不建议使用枚举Enum

最近优化App,由于项目中使用了Lib,而Lib代码中包含了大量的枚举类型,导致App占用内存过多发火。好吧,知道问题点,那就干掉,抛弃之~偷笑 问题是解决了,为啥会这样呢?疑问 先来看看Android官网的说明吧: 看见了吧,Android官网不建议咱们使用enums,说的也很清楚了,占用内存多(Enums often require more than twice as much memo

C# step by step 学习笔记8 CHAPTER 9 使用枚举和结构创建值类型

C# 2012 step by step 学习笔记8 CHAPTER 9 使用枚举和结构创建值类型 本章内容 声明一个枚举类型创建并使用一个枚举类型声明一个结构类型创建并使用一个结构类型解释结构和类之间行为的差别 声明一个枚举         enum Season { Spring, Summer, Fall, Winter } 使用枚举         You

洛谷 P1141 01迷宫 (dfs解决)

题目描述 有一个仅由数字 0 与 1 组成的 n×n 格迷宫。若你位于一格 0 上,那么你可以移动到相邻 4 格中的某一格 1 上,同样若你位于一格 1 上,那么你可以移动到相邻 4 格中的某一格 0 上。 你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。 输入格式 第一行为两个正整数 𝑛,𝑚。 下面 𝑛 行,每行 𝑛 个字符,字符只可能是 0 或者

[HDU 4324] Triangle LOVE (拓扑排序,DFS)

HDU - 4324 题意是,一张有 N个点的图,保证每两个点之间有且只有一条有向边连接 求是否存在三元环 用拓扑排序判环,如果存在环,则一定存在三元环 证明如下: 不存在二元环 设存在 n(n>=3)元环 p1->p2->p3->…->pn->p1 1) 若存在边 p3->p1,则存在三元环 (p1->p2->p3->p1) 2) 若不存在 p3->p1,则必然存在 p1->p3

[CSU - 1811 (湖南省赛16)] Tree Intersection (dfs序维护子树+离线询问+树状数组)

CSU - 1811 (湖南省赛16) 给定一棵树,每个节点都有一个颜色 问割掉任意一条边,生成的两个子树中颜色集合的交集大小 这个是 dfs序处理子树 + 离线询问 + bit维护 的解法 首先问题转化为求解一个子树中有多少种颜色以及独有颜色的数量 用总的颜色数量减去独有颜色数量即为这棵子树的答案 先做一遍 dfs,再按 dfs序重新组建颜色序列 这样对子树的询问,就变成