收购计划
时间限制(普通/Java) :
2000 MS/ 6000 MS 运行内存限制 : 16384 KByte
总提交 : 292 测试通过 : 26
总提交 : 292 测试通过 : 26
题目描述
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
解题思路:深搜+枚举+剪枝。从n-1枚举选择的公司个数,dfs满足条件时跳出循环,确保n为最大值。
代码如下:
#include <cstdio>
#include <cstring>
int a[43],vis[43];//vis用来标记是否选到,初始为都选到。
int num,n,k;
bool dfs(int sum,int cnt,int j)//sum 表示当前选择的总人数,cnt表示当前选择的公司总数,j表示起始下标。
{
if(sum>=k && sum%k==0 && cnt==num)
return true;
if(cnt<=num) //目标个数是num。cnt<=num时,cnt不必再往下减,
return false;
for(int i=j;i<=n;i++)
{
if(vis[i])continue;
vis[i]=1; //标记为不选
if( sum-a[i] && dfs(sum-a[i],cnt-1,i+1))
return true;
vis[i]=0; //还原
}
return false;
}
int main()
{
int i,t;
scanf("%d",&t);
while(t--)
{
int sum=0;
num=0;
scanf("%d%d",&n,&k);
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
for(i=n;i>=1;i--) //枚举应选的公司个数
{
num=i;
if(dfs(sum,n,1))
break;
}
printf("%d\n",num);
}
return 0;
}