NBUT 1743-WC的简单贪心【枚举+贪心】 难度:**

题意:

给出n个a[i],b[i], 要求选出不多于A个a[i],不多于B个b[i],(选择a[i]就不能选择b[i]),使得两者总和的和最大
输入
一个T,表示有T组数据
三个数n,A,B
n个数,表示a[i]
n个数,表示b[i]

1 <= A,B <= n <= 20
1 <= a[i],b[i] <= 1e5
输出
T个数,表示所求的最大值
样例输入
1
5 3 3
1 2 3 4 5
5 4 3 2 1
样例输出
21

题解:

已给两个数列,先用二进制枚举来枚举第一个数列所有的抽取的情况,然后对于每一种枚举出来的情况,对第二个数列贪心选取那些对应位置没有被选择的最大的几个数。
一些优化建议:
1、如果第一个数列抽取了p个数且p<A,而p+B<n,那么这种情况一定不是最大,可以直接跳过了;
2、二进制枚举可以从2(n-B)-1开始枚举(而不是0),因为比这小的情况一定不满足第一条建议
3、二进制枚举可以到2n-2(n-A)结束(而不是2n),因为比这大的情况选择的数量超额了

代码:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
struct node
{
	int p;
	int q;
	int mark;
}num[22],nums[22];
int inc(const void *a, const void *b)
{
    struct node m = *(struct node *)a;
    struct node n = *(struct node *)b;
    if(m.mark!=n.mark) return m.mark-n.mark;
    else return n.q-m.q;
}
int main()
{
	int t,n,a,b,max,sum,total,times;
	int length;
	scanf("%d",&t);
	while(t--)
	{
		max=0;
		scanf("%d%d%d",&n,&a,&b);
		for(int i=0;i<n;i++)scanf("%d",&num[i].p);
		for(int i=0;i<n;i++)scanf("%d",&num[i].q);
		for(int i=0;i<n;i++)num[i].mark=0;
		length=(pow(2,n))-(pow(2,n-a));
		for(unsigned int k=0;k<=length;k++)
		{
			for(int i=0;i<n;i++)nums[i]=num[i];
			total=0;
			times=0;
			sum=0;
			int temp=k;
			while(temp)
			{
				if(temp&1)
				{
					total++;
					sum+=nums[times].p;
					nums[times].mark=1;
				}
				times++;
				temp/=2;
				if(times>n||total>=a)break;
			}
			if(total+b<n&&total<a)continue;
			else
			{
				int bb=b;
				qsort(nums,n,sizeof(struct node),inc);
				for(int i=0;i<20;i++)
				{
					if(nums[i].mark==0&&bb)
					{
						sum+=nums[i].q;
						bb--;
					}
					else break;
				}
			}
			if(sum>=max)max=sum;
		}
		printf("%d\n",max);
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_42921101/article/details/104322167