51Nod-1112-KGold(直线相交)

题目来源:  UVALive 5868
基准时间限制:1 秒 空间限制:131072 KB 分值: 40  难度:4级算法题
 收藏
 关注
给出N个人在0时刻的财富值M[i](所有人在0时刻的财富互不相等),以及财富增长速度S[i],随着时间的推移,某些人的财富值会超越另外一些人。如果时间足够长,对于财富增长最快的人来说,他的财富将超越所有其他对手。
求发生的前10000次超越,分别是谁超过了谁?如果总的超越次数不足10000,则输出所有超越,如果1次超越都不会发生,则输出No Solution。
输出按照超越发生的时间排序,同一时刻发生的超越,按照超越者的编号排序,如果编号也相同,则按照被超越者的编号排序。所有排序均为递增序。
Input
第1行:N,表示人的数量。(1 <= N <= 10000)
第2 - N + 1行:每行2个数,分别是初始的财富值M[i],和财富增长速度S[i]。(0 <= M[i] <= 10^5, 1 <= S[i] <= 100)
Output
输出前10000次超越,超越者和被超越者的编号。如果总的超越次数不足10000,则输出所有。如果1次超越都不会发生,则输出No Solution。
输出按照超越发生的时间排序,同一时刻发生的超越,按照超越者的编号排序,如果超越者编号也相同,则按照被超越者的编号排序。所有排序均为递增序。
Input示例
4
1 100
2 100
3 1
4 50
Output示例
2 3
1 3
2 4
1 4
李陶冶  (题目提供者)
这题可以简单转化为求直线交点问题,当且仅当财富值m[i]<m[j]并且增长值s[i]>s[j]时才会发生超越
因此  find函数里找到当前时间下,每个点超越(或者被超越了几次)->这里二分一下即可,剩下的用
一个优先队列存储即可(n^2存点,侥幸通过)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<limits.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<math.h>
#include<string>
#include<map>
using namespace std;
#define maxn 10005
#define eps 1e-8
using namespace std;
struct Res
{
	int b,k,id;
	bool operator <(const Res &c) const
	{
		if(b>c.b)
			return 1;
		return 0;
	}
}s[maxn];
struct Coin
{
	double y;
	int id;
	bool operator <(const Coin &b) const
	{
		if(y>b.y)
			return 1;
		return 0;
	}
}c[maxn];
struct Point
{
	double p;
	int x,y;
	bool operator <(const Point &b) const
	{
		if(p>b.p || fabs(p-b.p)<eps && x>b.x || fabs(p-b.p)<eps && x==b.x && y>b.y)
			return 1;
		return 0;
	}
}now;
priority_queue<Point>q;                 
int n;
int find(double x)//判断x秒时,每个人的财富超过了多少人的财富
{
	int i,sum=0;
	for(i=1;i<=n;i++)
	{
		c[i].id=i;
		c[i].y=s[i].b+s[i].k*x;
	}
	sort(c+1,c+n+1);
	for(i=1;i<=n;i++)
		if(i<c[i].id)//表明这个人超过了一定数量的人
			sum+=c[i].id-i;
	return sum;
}
int  main()
{
	int i,j;
	double x,l,r,m;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&s[i].b,&s[i].k);
		s[i].id=i;
	}
	sort(s+1,s+n+1);
	l=1;r=1000005;
	while(r-l>0.00001)
	{
		m=(l+r)/2;
		if(find(m)>10000)
			r=m;
		else
			l=m;
	}
	for(i=2;i<=n;i++)
		for(j=1;j<i;j++)
		{
			x=1.0*(s[j].b-s[i].b)/(s[i].k-s[j].k);
			if(x>eps && x<r)
			{
				now.p=x;
				now.x=s[i].id;
				now.y=s[j].id;
				q.push(now);
			}
		}
	for(i=1;i<=10000;i++)
	{
		if(!q.empty())
		{
			printf("%d %d\n",q.top().x,q.top().y);
			q.pop();
		}
		else
			break;
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值