POJ 2785 4 Values whose Sum is 0

题目大意:

        有a、b、c、d四列数,各列元素数量相同,先从每列中挑出一个元素,使之相加之和为0,问共有多少个这样的四元组。

        只有一个测例,测例中会告诉列长n(1 ≤ n ≤ 4,000),每个元素的范围为[-2^28, 2^28],求其相加等于0的四元组的数量。

题目链接

开放地址Hash:

注释代码:

/*                              
 * Problem ID : POJ 2785 4 Values whose Sum is 0
 * Author     : Lirx.t.Una                              
 * Language   : C                 
 * Run Time   : 1579 ms                              
 * Run Memory : 125528 KB                              
*/ 

#include <stdio.h>

//最大值2^28 + 1
#define	INF			268445357
//模数取4000 × 4000以下的最大素数
#define	MOD			15999989

//maximum number of lines
//最大行数
#define	MAXLINEN	4000

typedef	struct	{//哈希表中的元素

	int		sum;//表示该等于该键值的元素共有多少个
	int		val;//value,即key,键值
} Hash;

Hash		hash[MOD];//哈希表
//表示a、b、c、d四列数据
int			a[MAXLINEN];
int			b[MAXLINEN];
int			c[MAXLINEN];
int			d[MAXLINEN];

void
Insert(int val) {//插入哈希表

	int		i;

	i = val % MOD;//将Hash键值降到MOD以内

	if ( i < 0 )//修正Hash键值使之满足数组下标的要求
		i += MOD;
	//hash[i].sum == 0就表示哈希表中该位置为空可以填入
	//而hash[i].sum && hash[i].val == val表示该位置已经插入过当前元素了
	//hash[i].sum && hash[i].val != val表示该位置被其它元素占去,即发生冲突,因此需要调整i的位置
	while ( hash[i].sum && hash[i].val != val )
		i = ( i + 1 ) % MOD;//加1取模法

	hash[i].sum++;
	hash[i].val = val;
}

int
Find(int val) {//对指定元素哈希查找,获得该元素在表中的个数
	
	int		i;
	
	i = val % MOD;
	
	if ( i < 0 )
		i += MOD;
	while ( hash[i].sum && hash[i].val != val )
		i = ( i + 1 ) % MOD;
	
	return hash[i].sum;
}

int
main() {
	
	int		n;//表示一共有n行
	int		i, j;
	//previous element,sum of previous round
	//上一轮查找的元素值和上一轮查找的元素在哈希表中的个数
	int		pre, pres;
	int		tmp;//temporary,临时变量
	int		ans;
	
	scanf("%d", &n);
	
	for ( i = 0; i < n; i++ )
		scanf("%d%d%d%d", a + i, b + i, c + i, d + i);
	
	//先对前两列元素的两两和建立哈希表
	for ( i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ )
			Insert( a[i] + b[j] );
		
	//在哈希表中逐个查询后两列两两和的相反数的个数,累加即可
	for ( ans = 0, pre = INF, pres = 0, i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ ) {
				
			//若和上一轮查询的元素相同,则可以直接利用上一轮的结果避免重新查询
			tmp = -( c[i] + d[j] );
			if ( tmp == pre ) {
					
				ans += pres;
				continue;
			}
				
			pre  = tmp;
			pres = Find(tmp);
			ans += pres;
		}
			
	printf("%d\n", ans);
			
	return 0;
}

无注释代码:

#include <stdio.h>

#define	INF			268445357
#define	MOD			15999989

#define	MAXLINEN	4000

typedef	struct	{

	int		sum;
	int		val;
} Hash;

Hash		hash[MOD];
int			a[MAXLINEN];
int			b[MAXLINEN];
int			c[MAXLINEN];
int			d[MAXLINEN];

void
Insert(int val) {

	int		i;

	i = val % MOD;

	if ( i < 0 )
		i += MOD;
	while ( hash[i].sum && hash[i].val != val )
		i = ( i + 1 ) % MOD;

	hash[i].sum++;
	hash[i].val = val;
}

int
Find(int val) {

	int		i;

	i = val % MOD;

	if ( i < 0 )
		i += MOD;
	while ( hash[i].sum && hash[i].val != val )
		i = ( i + 1 ) % MOD;

	return hash[i].sum;
}

int
main() {

	int		n;
	int		i, j;
	int		pre, pres;
	int		tmp;
	int		ans;

	scanf("%d", &n);

	for ( i = 0; i < n; i++ )
		scanf("%d%d%d%d", a + i, b + i, c + i, d + i);

	for ( i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ )
			Insert( a[i] + b[j] );

	for ( ans = 0, pre = INF, pres = 0, i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ ) {
		
			tmp = -( c[i] + d[j] );
			if ( tmp == pre ) {

				ans += pres;
				continue;
			}

			pre  = tmp;
			pres = Find(tmp);
			ans += pres;
		}
		
	printf("%d\n", ans);
		
	return 0;
}

二分搜索:

注释代码:

/*                              
 * Problem ID : POJ 2785 4 Values whose Sum is 0
 * Author     : Lirx.t.Una                              
 * Language   : C                 
 * Run Time   : 7610 ms                              
 * Run Memory : 24672 KB                              
*/ 

#include <stdlib.h>
#include <stdio.h>

#define	INF				268435457

#define	MAXLINEN		4000
//maximum number of sum lines
//两两相加和的总数
//4,000 × 4,000
#define	MAXSUMN			16000000

int		a[MAXLINEN];
int		b[MAXLINEN];
int		c[MAXLINEN];
int		d[MAXLINEN];

int		ab[MAXSUMN];//存放a、b两两相加的和

int
fcmp(const void *a, const void *b) {
	
	return *(int *)a - *(int *)b;
}

int
main() {
	
	int		n;
	int		i, j, k;
	int		p;
	int		tmp;
	int		pre, pres;
	int		ans;
	
	int		lft, rht, mid;
	
	scanf("%d", &n);
	
	for ( i = 0; i < n; i++ )
		scanf("%d%d%d%d", a + i, b + i, c + i, d + i);
	
	for ( p = 0, i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ )
			ab[p++] = a[i] + b[j];
		
	qsort(ab, p, sizeof(int), &fcmp);//对ab进行升序排列为后面进行二分查找做准备
		
	for ( ans = 0, pre = INF, pres = 0, i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ ) {
				
			tmp = -( c[i] + d[j] );
				
			if ( tmp == pre ) {
					
				ans += pres;
				continue;
			}
				
			lft = 0;
			rht = p - 1;
				
			pre  = tmp;
			pres = 0;
				
			while ( lft <= rht ) {//二分查找
					
				mid = ( lft + rht ) >> 1;
					
				if ( tmp == ab[mid] ) {
						
					pres++;
					
					//左右两旁可能有同值元素,统统都要算上
					for ( k = mid + 1; k < p && tmp == ab[k]; k++ )
						pres++;
					for ( k = mid - 1; k >= 0 && tmp == ab[k]; k-- )
						pres++;
						
					ans += pres;
						
					break;
				}
					
				if ( tmp < ab[mid] )
					rht = mid - 1;
				else
					lft = mid + 1;
			}
		}
			
		printf("%d\n", ans);
			
		return 0;
}

无注释代码:

#include <stdlib.h>
#include <stdio.h>

#define	INF				268435457

#define	MAXLINEN		4000
#define	MAXSUMN			16000000

int		a[MAXLINEN];
int		b[MAXLINEN];
int		c[MAXLINEN];
int		d[MAXLINEN];

int		ab[MAXSUMN];

int
fcmp(const void *a, const void *b) {

	return *(int *)a - *(int *)b;
}

int
main() {

	int		n;
	int		i, j, k;
	int		p;
	int		tmp;
	int		pre, pres;
	int		ans;

	int		lft, rht, mid;

	scanf("%d", &n);

	for ( i = 0; i < n; i++ )
		scanf("%d%d%d%d", a + i, b + i, c + i, d + i);

	for ( p = 0, i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ )
			ab[p++] = a[i] + b[j];

	qsort(ab, p, sizeof(int), &fcmp);

	for ( ans = 0, pre = INF, pres = 0, i = 0; i < n; i++ )
		for ( j = 0; j < n; j++ ) {
		
			tmp = -( c[i] + d[j] );

			if ( tmp == pre ) {
			
				ans += pres;
				continue;
			}

			lft = 0;
			rht = p - 1;

			pre  = tmp;
			pres = 0;

			while ( lft <= rht ) {
			
				mid = ( lft + rht ) >> 1;

				if ( tmp == ab[mid] ) {
				
					pres++;

					for ( k = mid + 1; k < p && tmp == ab[k]; k++ )
						pres++;
					for ( k = mid - 1; k >= 0 && tmp == ab[k]; k-- )
						pres++;

					ans += pres;

					break;
				}

				if ( tmp < ab[mid] )
					rht = mid - 1;
				else
					lft = mid + 1;
			}
		}

	printf("%d\n", ans);

	return 0;
}

单词解释:

formulate:vt, 用公式表示,明确表达

list:n, 列表,一列

quagruplet:n, 四胞胎,四元组

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值