算法设计与分析 4.4 洪尼玛与魔法卡

★题目描述

洪尼玛有2n张魔法卡,每张魔法卡上都有两个正整数a、b。

洪尼玛准备将这些魔法卡平均分成2堆,每堆有n张魔法卡。

一堆魔法卡所能发挥的功力值为该堆魔法卡中最小的a值与最小的b值的乘积。

洪尼玛有一种X能力,可以使某张魔法卡上的a、b值互换,并且可以无限次使用这个能力。

洪尼玛想知道将这些魔法卡平均分成2堆后(可以使用X能力),这2堆魔法卡一共能发挥的最大功力值是多少?

★输入格式

接下来2n行,每行两个正整数ai、bi,表示每张魔法卡上的两个值;

对于60%的数据,1<=n<=103;

对于100%的数据,1<=n<=105、1<=ai、bi<=109。

★输出格式

输出一个正整数,表示最大功力值。

★样例输入

2
1 2
3 4
5 6
7 8

★样例输出

32

★提示

★参考代码

思路参考共享文件

/*
假设最大功力值为 a1*b1 + a2*b2 
1.为了减少考虑的情况,在接受输入时让每张卡片上a统一小于b
2.按照a值对所有卡片升序排列 
3.因为题目要求两堆卡片数量都为n,所以可确定:
	第一堆最小a值(即a1)为a边最小的值
	第二堆最小a值最大化(即a2最大)只可能为a边第n+1小的值
	
		注意:第二堆的a值不能直接定为a边第n+1小的值,因为你考虑下面一种情况,有4张卡
		2  10 
		4  100
		6  11 
		8  110 
		那么最佳的应该是 2*10 + 4*100
		
	所以可以确定寻找a2应该枚举,遍历第2张到第n+1张卡片,然后看那种组合能得到最大res	

4.在确定a1,a2情况下要如何确定左右两堆的最小b值(即b1、b2)
	b1\b2肯定有一者是b边的最小值,所以这两种情况都要尝试 

        思路:
	可以确定的是a1为a边最小值,然后: 
	第一种情况,b边最小值在第一堆,那么b1为b边最小值,然后枚举a2,最大化b2
	第二种情况,b边最小值在第二堆,那么b2为b边最小值,然后枚举a2,最大化b1
 
	for k in [2,n+1]  //因为已经按a排好序,在前k张放在第1堆,第k张放在第2堆的情况下 
		a2 = C[k].a //第k张的a值即为第二堆的最小值 
		
		if b1为b边最小值,那么最大化b2
			从剩下的 [k+1, 2*n] 张卡片中找出b边尽可能大的n-1张卡放在第二堆 
			b2 = min(C[k].b, 剩下第k+1到2*n张卡片中b边第n-1大的值) 

		if b2为b边最小值,那么最大化b1
			从剩下的 [k+1, 2*n] 张卡片中找出b边尽可能大的n-k+1张卡放在第一堆
			b1 = min(第[1,k-1]张卡的b边最小值, 从剩余的第[k+1,2*n]张卡选出b边第n-k+1大的值) 
*/
#include<bits/stdc++.h>
using namespace std;

int n;
struct Card{
	int a,b;
	bool operator < (const Card Y) const{return a==Y.a ? b<Y.b : a<Y.a;}
}C[200000+5];
int min_b=0x7FFFFFFF, pre_min_b[100000+5]={0x7FFFFFFF}; //记录从1到n的前缀最小值 

int main(){
	scanf("%d",&n);
	
 	for(int i=1; i<=2*n; ++i){
		scanf("%d%d",&C[i].a, &C[i].b);
		if(C[i].a>C[i].b) swap(C[i].a, C[i].b);
		min_b = min(min_b, C[i].b); //b边最小值 
	}
	
	sort(C+1, C+2*n+1);
	int a1 = C[1].a; //a边最小值为a1 
	for(int i=1; i<=n; ++i) pre_min_b[i]=min(pre_min_b[i-1], C[i].b);//排序后的,b边前缀最小 


	priority_queue<int> q1; //降序优先队列,用于最大化b1,长度在变小 
	priority_queue<int, vector<int>, greater<int> > q2; //升序优先队列,用于最大化b2,长度固定为n-1 
 	for(int i=n+2; i<=2*n; ++i) q1.push(C[i].b),q2.push(C[i].b); 
	
	int res=0, a2, b1, b2;
	for(int k=n+1; k>1; --k){ //前k-1张卡片放在第1堆中,第k张卡片放在第2堆中 
		a2 = C[k].a;

		//b1为b边最小值,最大化b2 
		b1 = min_b;
		b2 = min(C[k].b, q2.top());
		res = max(res, a1*b1+a2*b2);
		
		//b2为b边最小值,最大化b1
		b2 = min_b;
		if(k==n+1) b1 = pre_min_b[n];
		else {
			b1 = min(pre_min_b[k-1], q1.top());
			q1.pop();
		}
		res = max(res, a1*b1+a2*b2);
		
		q1.push(C[k].b);
		q2.push(C[k].b); 
		if(q2.size()>=n) q2.pop(); 
	}
	
	printf("%d\n", res);
	return 0;
}

posted on 2019-12-22 01:25  yejifeng  阅读(1065)  评论(0编辑  收藏  举报

导航