PAT DS 506 航空公司VIP客户查询

7 篇文章 0 订阅

这题时间限制的紧(150ms),导致第一种红黑树的办法最后一个case超时(第二个case用了149ms,汗。。。)。

红黑树的办法就是逐个添加到树里,在ins_update函数里调整,使之符合红黑树规则。具体参见《算法导论》。代码参看附录A。

想到过会不会是strcmp比较费时间,可是简单测试过之后发现,长度为18的字符串之间的strcmp并不比整型数的比较慢多少。见下图(图中数值均为clock_t):


代码参看附录B。

幸好,最后想到应该用hash表来做。便写个简易的hash函数,将身份证号按3,3,4,4,4个数相加,再对10求余,正好10的5次方数量级。代码见附录C。


后记:

粗略算一下的话,红黑树时间复杂度为nlogn数量级,我这个程序大约是n(10+10logn),10^5数据量的话便大约是10^7。加上一条语句大约几个指令,一条指令需要几个到几十个时钟周期,最后便大约是10^8数量级的时钟周期。150ms大约也是10^8时钟周期。CPU是3GHz的话,需要333ms才比较保险,所以是危险的。


附录A:

<span style="font-size:18px;">#include <stdio.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>

int n, k, m;

typedef struct mem{
	char id[19];
	long ma;		// mileage
	struct mem *le, *ri, *pa;	// left, right, parent
	bool color;		// true if red, false if black
}Mem;
Mem NIL = {"", 0, NULL, NULL, NULL, false};
Mem *rbtree, *pNIL = &NIL;	// red-black tree, ..

void insert(char *id, long ma);
bool search(char *id, Mem **ppm);

int main(void)
{
#ifdef DEBUG
	freopen("in.txt", "r", stdin);
#endif
	rbtree = pNIL;
	scanf("%d%d", &n, &k);
	int i=0;
	Mem *pm;
	for(; i<n; ++i){
		char tid[19];
		long tma;
		scanf("%s%ld", tid, &tma);
#ifdef DEBUG
		printf("debug: %s %ld\n", tid, tma);
#endif
		if(tma < k)
			tma = k;
		insert(tid, tma);
	}
	scanf("%d", &m);
	for(i=0; i<m; ++i){
		char tid[19];
		scanf("%s", tid);
		if(search(tid, &pm)){
			assert(pm != pNIL && pm != NULL);
#ifdef DEBUG
			printf("%s: ", pm->id);
#endif
			printf("%ld\n", pm->ma);
		}
		else
			printf("No Info\n");
	}
	return 0;
}

bool search(char *id, Mem **ppm)
{
	*ppm = rbtree;
#ifdef DEBUG
	printf("\nsearch: %s\n", id);
#endif
	while(*ppm != pNIL){
#ifdef DEBUG
		printf("%s %ld\n", (*ppm)->id, (*ppm)->ma);
#endif
		int sc = strcmp(id, (*ppm)->id);
		if(sc == 0)
			return true;
		else if(sc < 0)
			*ppm = (*ppm)->le;
		else
			*ppm = (*ppm)->ri;
	}
	return false;
}

void left_rotate(Mem *pm);
void right_rotate(Mem *pm);
void ins_update(Mem *pm);

void insert(char *id, long ma)
{
	Mem *px = rbtree, *py = pNIL;
	int sc;
	while(px != pNIL){
		py = px;
		sc = strcmp(id, px->id);
		if(sc == 0){
			px->ma += ma;
			return;
		}
		else if(sc < 0)
			px = px->le;
		else
			px = px->ri;
	}
	Mem *pm = (Mem*)malloc(sizeof(Mem));
	if(pm == NULL)
		exit(1);
	strcpy(pm->id, id);
	pm->ma = ma;
	pm->le = pm->ri = pNIL;
	pm->pa = py;
	pm->color = true;
	if(py == pNIL)
		rbtree = pm;
	else if(sc < 0)
		py->le = pm;
	else
		py->ri = pm;
	ins_update(pm);
}

void ins_update(Mem *z)
{
	Mem *y;
	while(z->pa->color){
		if(z->pa == z->pa->pa->le){
			y = z->pa->pa->ri;
			if(y->color){
				z->pa->color = false;
				y->color = false;
				z->pa->pa->color = true;
				z = z->pa->pa;
			}
			else{
				if(z == z->pa->ri){
					z = z->pa;
					left_rotate(z);
				}
				z->pa->color = false;
				z->pa->pa->color = true;
				right_rotate(z->pa->pa);
			}
		}
		else{
			y = z->pa->pa->le;
			if(y->color){
				z->pa->color = false;
				y->color = false;
				z->pa->pa->color = true;
				z = z->pa->pa;
			}
			else{
				if(z == z->pa->le){
					z = z->pa;
					right_rotate(z);
				}
				z->pa->color = false;
				z->pa->pa->color = true;
				left_rotate(z->pa->pa);
			}
		}
	}
	rbtree->color = false;
}

void left_rotate(Mem *z)
{
	assert(z != pNIL && z->ri != pNIL);
	Mem *y = z->ri;
	z->ri = y->le;
	if(y->le != pNIL)
		y->le->pa = z;
	y->pa = z->pa;
	if(z->pa == pNIL)
		rbtree = y;
	else if(z == z->pa->le)
		z->pa->le = y;
	else
		z->pa->ri = y;
	y->le = z;
	z->pa = y;
}

void right_rotate(Mem *z)
{
	assert(z != pNIL && z->le != pNIL);
	Mem *y = z->le;
	z->le = y->ri;
	if(y->ri != pNIL)
		y->ri->pa = z;
	y->pa = z->pa;
	if(z->pa == pNIL)
		rbtree = y;
	else if(z == z->pa->ri)
		z->pa->ri = y;
	else
		z->pa->le = y;
	y->ri = z;
	z->pa = y;
}
</span>

附录B:

<span style="font-size:18px;">#include <stdio.h>
#include <string.h>
#include <time.h>

char id[10000000][19];
int main(void)
{
	clock_t start, finish;
	long i=0, j;
	for(i=0; i<10000000; ++i)
		sprintf(id[i], "%18ld", i);

	start = clock();
	for(i=1; i<10000000; ++i)
		j = strcmp(id[i], id[i-1]);
	finish = clock();
	printf("strcmp: %ld %ld %ld\n", start, finish, (finish-start));

	start = clock();
	for(i=1; i<10000000; ++i){
		j = id[i][0] > id[i-1][0];
		j = id[i][1] > id[i-1][1];
	}
	finish = clock();
	printf("long: %ld %ld %ld\n", start, finish, (finish-start));
	return 0;
}</span>


附录C:

<span style="font-size:18px;">#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>

int n, k, m;

typedef struct s_mem{
	char id[19];
	long ma;
	struct s_mem *next;
}Mem;
Mem *ht[100000];		// hash table

long hash(char *id);
void insert(char *id, long ma);		// mileage

int main(void)
{
#ifdef DEBUG
	freopen("in.txt", "r", stdin);
#endif
	memset(ht, 0, sizeof(ht));
	scanf("%d%d", &n, &k);
	int i=0;
	for(i=0; i<n; ++i){
		char tid[19];
		long tma;
		scanf("%s%ld", tid, &tma);
		if(tma < k)
			tma = k;
		insert(tid, tma);
#ifdef DEBUG
		printf("\ninsert %s & hash table:\n", tid);
		long j=0;
		for(; j<100000; ++j){
			Mem *dpm = ht[j];
			while(dpm != NULL){
				printf("%ld: %s %ld\n", j, dpm->id, dpm->ma);
				dpm = dpm->next;
			}
		}
#endif
	}
	scanf("%d", &m);
	for(i=0; i<m; ++i){
		char tid[19];
		scanf("%s", tid);
		long h = hash(tid);
		Mem *pm = ht[h];
		while(pm != NULL){
			if(strcmp(tid, pm->id)==0){
				printf("%ld\n", pm->ma);
				break;
			}
			else
				pm = pm->next;
		}
		if(pm == NULL)
			printf("No Info\n");
	}
	return 0;
}

long hash(char *id)
{
	long h = (id[0]+id[1]+id[2])%10*10000;
	h += (id[3]+id[4]+id[5])%10*1000;
	h += (id[6]+id[7]+id[8]+id[9])%10*100;
	h += (id[10]+id[11]+id[12]+id[13])%10*10;
	h += (id[14]+id[15]+id[16]+id[17])%10;
	return h;
}

void insert(char *id, long ma)
{
	long h = hash(id);
	Mem *pm = ht[h], *pre=ht[h];
	while(pm != NULL){
		pre = pm;
		if(strcmp(id, pm->id) == 0){
			pm->ma += ma;
			return;
		}
		else
			pm = pm->next;
	}
	if((pm = (Mem*)malloc(sizeof(Mem))) == NULL)
		exit(1);
	strcpy(pm->id, id);
	pm->ma = ma;
	if(pre != NULL)
		pre->next = pm;
	else
		ht[h] = pm;
}
</span>


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值