Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

雁过留声——快速排序之惑

Posted by fanhqme at 2010-02-18 18:33:31 on Problem 3168
这题的算法其实是非常简单的。
由于没有overlap,所以只用考虑有公共边与公共点的情况就行了。
先考虑平行与y轴的公共边,
把所有的数按x排序,之后只考虑x相同的边。
随便使用一种扫描的方法来判断若干个区间是否有公共部分就行了。
具体的可以看代码。
考虑平行与x轴的公共边同理。
为了简化,可以把公共点理解为长度为0的公共边,这样也一并解决了。

关键就是排序。
我拿出了我喜欢的屡试不爽的经典的quicksort的写法:
#define Swap(u,v) {t=rank[u];rank[u]=rank[v];rank[v]=t;}
void qs(int b,int e){if (b>=e)return;
	static int j,t;
	Swap(b,(b+e)>>1);
	for (int i=j=b+1;i<=e;i++)if (A[rank[i]]<A[rank[b]] ||
		A[rank[i]]==A[rank[b]] && (B[rank[i]]<B[rank[b]] || B[rank[i]]==B[rank[b]] && (i&1))){
			Swap(i,j);
			j++;
		}
	--j;
	Swap(b,j);
	qs(b,j-1);qs(j+1,e);
}
这里加入了不少抗恶心数据(例如已经排好序的,或者全都一样的)的方法,
所以还没有什么排序题能卡住它。
然而,TLE了?!
出于对自己扫描能力的信任,我判断是快排导致了超时。
然而,在百度上搜索这题,发现有人是用快排过的。
(http://old.blog.edu.cn/user4/bitacmer/archives/2007/1723278.shtml)
这是怎么回事?
再仔细看了看他的代码,使用的是库函数,其他地方倒与我的没有两样。
那为什么快速排序也能一个t一个A呢?
我开始怀疑自己喜欢的经典快排的常数,并且猜测是由于rank的使用以及
坑恶心导致的。

AC才是王道。我祭出了排序的终极武器:基数排序。
void rs(int n){
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[B[i]&1023]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[B[rank[i]]&1023]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[B[i]>>10]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[B[rank[i]]>>10]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[A[i]&1023]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[A[rank[i]]&1023]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[A[i]>>10]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[A[rank[i]]>>10]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
}
实践证明,过了,并且速度比那个快排的人快2倍。
我没有使用计数排序的原因是担心数据范围太大(0~1000000),
如果case数量达到100个以上恐怕吃不消。
这题让我见识了:写快排也有好坏之分,并不是每个人的排序都一样好。

示例代码:
void rs(int n){
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[B[i]&1023]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[B[rank[i]]&1023]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[B[i]>>10]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[B[rank[i]]>>10]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[A[i]&1023]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[A[rank[i]]&1023]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
	memset(cnt,0,sizeof(cnt));
	for (int i=0;i<n;i++)cnt[A[i]>>10]++;
	for (int i=1;i<1024;i++)cnt[i]+=cnt[i-1];
	for (int i=n-1;i>=0;i--)buf[--cnt[A[rank[i]]>>10]]=rank[i];
	memcpy(rank,buf,n*sizeof(rank[0]));
}


	scanf("%d",&N);
	for (int i=0;i<N;i++){
		scanf("%d %d %d %d",X1+i,Y1+i,X2+i,Y2+i);
		flag[i]=1;
	}
	for (int i=0;i<N;i++){
		A[i]=X1[i];B[i]=Y1[i];E[i]=Y2[i];I[i]=i;
		A[i+N]=X2[i];B[i+N]=Y1[i];E[i+N]=Y2[i];I[i+N]=i;
	}
	for (int i=0;i<N+N;i++)rank[i]=i;
	rs(N+N);
	for (int i=0;i<N+N;i=k){
		k=i;
		while (k<N+N && A[rank[i]]==A[rank[k]])k++;
		low=-1;
		for (int j=i;j<k;j++){
			if (j!=k-1 && E[rank[j]]>=B[rank[j+1]])flag[I[rank[j]]]=0;
			if (B[rank[j]]<=low)flag[I[rank[j]]]=0;
			if (low<E[rank[j]])low=E[rank[j]];
		}
	}
	for (int i=0;i<N;i++){
		A[i]=Y1[i];B[i]=X1[i];E[i]=X2[i];I[i]=i;
		A[i+N]=Y2[i];B[i+N]=X1[i];E[i+N]=X2[i];I[i+N]=i;
	}
	for (int i=0;i<N+N;i++)rank[i]=i;
	rs(N+N);
	for (int i=0;i<N+N;i=k){
		k=i;
		while (k<N+N && A[rank[i]]==A[rank[k]])k++;
		low=-1;
		for (int j=i;j<k;j++){
			if (j!=k-1 && E[rank[j]]>=B[rank[j+1]])flag[I[rank[j]]]=0;
			if (B[rank[j]]<=low)flag[I[rank[j]]]=0;
			if (low<E[rank[j]])low=E[rank[j]];
		}
	}
	ret=0;
	for (int i=0;i<N;i++)ret+=flag[i];
	printf("%d\n",ret);

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator