uva 10763 Foreign Exchange(排序+二分查找)

这道题是我第一次算出来应该用什么复杂度写的题,或许是这一章刚介绍过,500000的数据必须用nlogn,所以我就

想到了二分,它的复杂度是logn,再对n个数据进行遍历,正好是nlogn,前两次TLE了,然后我就对我的做法没信心

了。。。看到一篇博客上说就应该这种方法,然后我就坚定的改自己的算法去了,哈哈,专注度没有达到五颗星,最多

三颗。。。

思路:

我用的是结构体保存的,先对每一对序列排序,然后对第二个元素在第一个元素中二分搜索,用到了

lower_bound,upper_bound,注释里面有写它的功能,其实这两个可以直接调用的。。。注意一下用

upper_bound的时候最后一个元素就ok啦。。。TLE其实不是我的算法的事,而是因为我把这两个函数写到循环里面

了,真傻。。。这样每次循环都会调用的。。。看网上有人说最后套数据n是小于1000的,加个if(n>1000)

for(;;;)就可以啦,哈哈,真聪明,我学会了。。。以后试着用一下。。

贴代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
struct node
{
	int i,j;
}a[500005];
int visit[500005];//用来标记是否已经配对过了 
int n;
int cmp(const void *a,const void *b)//结构体的二级排序 
{
	if(((node *)a)->i != ((node *)b)->i)
		return ((node *)a)->i - ((node *)b)->i;
	return ((node *)a)->j - ((node *)b)->j;
}
int lower_bound(int v)//二分查找,如果要查找的值存在的话,返回第一个等于该元素的位置,否则返回一个它要插入的第一个位置(序列必须先排序) 
{
	int m,x = 1,y = n;
	while(x < y )
	{
		m = x + (y-x)/2;
		if(a[m].i >= v) y = m ;
		else
			x = m + 1;
	}
	return x;
} 
int upper_bound(int v)//二分查找,如果存在该元素,就返回它的下一个位置(最后一个除外,就是说如果最后一个元素等于v,就返回的是n),如果不存在,就返回它插入后仍有序的序列 
{
	int m;
	int x = 1;
	int y = n;
	while(x < y)
	{
		m = x +(y -x)/2;
		if(a[m].i<=v) x = m+1;
		else
			y = m;
	}
	return x;
}
int main()
{
	int i,j;
	while(cin >> n, n)
	{
		memset(visit,0,sizeof(visit));
		for(i=1; i<=n; i++)
		{
		//	cin >> a[i].i >> a[i].j;//cin输入流比较费时 
			scanf("%d%d",&a[i].i,&a[i].j);
		}
		qsort(a+1,n,sizeof(a[0]),cmp);
	//	for(i=1; i<=n; i++)
	//	{
			//cin >> a[i].i >> a[i].j;
		//	scanf("%d%d",&a[i].i,&a[i].j);
	//		cout << a[i].i << " "<< a[i].j << endl;
	//	}
		int flag1 = 0;
		for(i=1; i<=n; i++)
		{
			if(visit[i] == 1)//配对过的不再访问 
				continue;
			int flag = 0;
			int first = lower_bound(a[i].j);
			int last = upper_bound(a[i].j);
		//	cout << "first = " << first << " " << last << endl;
			if(a[first].i != a[i].j)//没有与之配对的直接退出输出NO 
			{
				flag1 =1;
				break;
			}
			if(last == n)//把n的情况特判一下 
				last ++;
			for(j=first; j<last; j++)
			{
				if(visit[j] == 1)
					continue;
				if(a[j].j == a[i].i)
				{
					visit[j] = 1;
					flag = 1;
					break;
				}
			}
			if(!flag)
			{
				flag1 = 1;
				break;
			}
			visit[i] = 1;
		}
		if(flag1)
			cout << "NO" << endl;
		//	puts("NO");
		else
			cout << "YES" << endl;
			//puts("YES");
	} 
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值