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

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;
        else
            return 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");
    }
}
时间: 2024-12-09 00:57:37

NOJ 2030 收购计划 (枚举+DFS 好题)的相关文章

Oil Deposits(poj 1526 DFS入门题)

http://poj.org/problem?id=1562 Oil Deposits Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 12595   Accepted: 6868 Description The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp wor

leetcode中关于树的dfs算法题

Validate Binary Search Tree Recover Binary Search Tree Symmetric Tree Same Tree Maximum Depth of Binary Tree Construct Binary Tree from Preorder and Inorder Traversal Construct Binary Tree from Inorder and Postorder Traversal Convert Sorted Array to

DFS搜索题素数环

素数环: 输入整数1,2,3,4,5,···,n组成一个环,使得相邻两个整数之和均为素数. 输出时从整数1开始逆时针排列.同一个环应恰好输出一次.n<=16. Sample: input: 6 output: 1 4 3 2 5 6 1 6 5 2 3 4 使用DFS搜索解释:素数环的第一个数为1,则选定第一个数为1,然后向下遍历所有数据,能够和前面一个数据组合相加成为素数的数就被数组记录下来. 知道判断到最后一个数字,然后检查它和第一个数相加是否为素数,若是就输出数组中记录的答案,不是就从头开

HDU 1495 非常可乐(枚举+DFS)

非常可乐 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7094    Accepted Submission(s): 2826 Problem Description 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝

【DFS好题】BZOJ1999- [Noip2007]Core树网的核(数据加强版)

NOIP的数据好水,一开始有好几个错结果NOIP数据就水过了?? [题目大意] 求无根树的直径上一段不超过S长的链,使得偏心距最小.具体概念见原题. [思路] 首先明确几个性质: (1)对于树中的任意一点,距离其最远的点一定是树的直径的某一端点. (2)所有的直径是等价的,即任意一条所能求出的该最小偏心距相等. 于是我们可以用两次dfs求出直径.任取一个点找到离它最远的点r,再从r找到距离它最远的点l.l到r的路径就是直径. 显然在长度不超过S的情况下,链最长最好.在l到r上维护尽可能长的链,找

HDU 4770 Lights Against Dudely 暴力枚举+dfs

又一发吐血ac,,,再次明白了用函数(代码重用)和思路清晰的重要性. 11779687 2014-10-02 20:57:53 Accepted 4770 0MS 496K 2976 B G++ czy Lights Against Dudely Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1360    Accepted Subm

bzoj 3287: Mato的刷屏计划 高精水题 &amp;&amp; bzoj AC150

3287: Mato的刷屏计划 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 124  Solved: 43[Submit][Status] Description Mato同学喜欢上QQ,但是有少数傻逼总是问他一些弱智问题.Mato感到很反感,想要鄙视一下他们.他决定在QQ上刷屏,也就是发出一大堆字符.Mato的键盘上有4个键:A.B.C.D.按A就会输入一个字符,按B会把所有字符选中,按C会把选中的字符放入剪贴板,按D会插入剪贴板的内容.他的

DFS第二题

昨天学了DFS,今天自己做了一道题,从6点半到8点半,在提交时我还以为不会过,毕竟除了A+B的题,我没一次性AC过一道题,在测试最大数据时,黑框跑了34秒还没停下来,我以为我要超时了,但是并没有,好高兴. #include<iostream> #include<cstdio> #include<memory.h> using namespace std; int N; int temp[25],cir[25]; int is_prime(int x) //判断是否为素数

HDU 5752 Sqrt Bo【枚举,大水题】

Sqrt Bo Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2221    Accepted Submission(s): 882 Problem Description Let's define the function f(n)=⌊n−−√⌋. Bo wanted to know the minimum number y wh