HDU 6127 简化几何计数

17 篇文章 0 订阅


Hard challenge

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1116    Accepted Submission(s): 460


Problem Description
There are  n  points on the plane, and the  i th points has a value  vali , and its coordinate is  (xi,yi) . It is guaranteed that no two points have the same coordinate, and no two points makes the line which passes them also passes the origin point. For every two points, there is a segment connecting them, and the segment has a value which equals the product of the values of the two points. Now HazelFan want to draw a line throgh the origin point but not through any given points, and he define the score is the sum of the values of all segments that the line crosses. Please tell him the maximum score.
 

Input
The first line contains a positive integer  T(1T5) , denoting the number of test cases.
For each test case:
The first line contains a positive integer  n(1n5×104) .
The next  n  lines, the  i th line contains three integers  xi,yi,vali(|xi|,|yi|109,1vali104) .
 

Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.
 

Sample Input
      
      
2 2 1 1 1 1 -1 1 3 1 1 1 1 -1 10 -1 0 100
 

Sample Output
      
      
1 1100
 


题意 : 在平面直角坐标系上给出 n 个点,每个点带一个权值,两两点连线的权值为两个点权值的乘积,然后从原点发射一条直线(双向的)它获得的价值等于它穿过的直线段的价值的和。

要你求出最大值。

思路:题目有个重要条件,就是不会有两个点的连线经过原点,这个条件可以得出一个重要结论,就是你一定可以找到直线把所有的点分散在直线两边,形成两个点集,而不会出现两个点在直线上的情况,那么先把每个点计算出它的角度,然后按角度排个序,然后你只要对点给出一个判定条件(例如x坐标大于0)把点分成两部分,然后再依次把点放到另一个点集上,一边计算记录最大值就可以了。

计算的方法是先相加再相乘,如果一一对应相乘再相加的话,时间复杂度就超了。

#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<string.h>
using namespace std;
#define maxn 50005 
#define ll long long 
#define PI 3.14159265
#define eps 1e-9
struct node{
    double x,y,val,ang;
}p[maxn];
bool cmp(node a,node b){	//按照角度顺序排序 
	return a.ang < b.ang;
}
int main(){
    ll t,n,x,y,val,ang;
    ll tmp1,tmp2,ans;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        memset(p,0,sizeof(p));
        for(ll i = 1;i <= n;i++){
            scanf("%lf %lf %lf",&p[i].x,&p[i].y,&p[i].val);
            p[i].ang = atan(p[i].y / p[i].x); //根据tan值计算角度 
        }
        sort(p + 1,p + 1 + n,cmp);
        tmp1 = tmp2 = ans = 0;
        for(int i = 1;i <= n;i++){	//以x坐标大于0和小于0分成两部分  分别加到tmp1 和 tmp2 
        	if(p[i].x > eps)
        		tmp1 += p[i].val;	
        	else
        		tmp2 += p[i].val;
		}
		ans = tmp1 * tmp2;			// 两边的各个数相乘相加 = 相加 再 相乘 
		for(int i = 1;i <= n;i++){
			if(p[i].x > 0){
				tmp1 -= p[i].val;	// 在右边的就放到左边去 
				tmp2 += p[i].val;
			}else{
				tmp1 += p[i].val;	//在左边的就放到右边去 
				tmp2 -= p[i].val;
			}
			ans = max(ans,tmp1 * tmp2);		//每次记录最大的 
		}
		printf("%lld\n",ans);
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值