您的位置:首页 > 编程语言 > Go语言

POJ3274《Gold Balanced Lineup》方法:哈希

2013-03-25 19:30 239 查看
题目大意:最多有10w个牛,每个牛有最多30个特征,比如特征 10,可以表示为二进制形式1010,现在要求出在一个连续区间,牛的每个特征数目相等时,连续区间的最大长度。

解题思路:sum[i][j]表示从第1个到第i个牛,特征j出现的总数,即要求sum[a][0] - sum[b][0] = sum[a][1] - sum[b][1] = sum[a][k-1] - sum[b][k-1]。式子可转化为sum[a][1] - sum[a][0] = sum[b][1] - sum[b][0],sum[a][2] - sum[a][0]
= sum[b][2] - sum[b][0],因此可以令c[i][j] = sum[i][j] - sum[i][0],最终即要找到使c[a][]和c[b][]相等的区间最大长度。因为题目数量级为10w,因此不能两两之间相互比较,所以用哈希函数来将c[][]相等的数放入同一个地址中,具体的key是c[][1]*1+c[][2]*2...的和,prime取100003。

// 38236k 1079ms
#include <iostream>
#include <cstring>

using namespace std;

#define N 100003
#define K 30
const int prime = 100003;

class HashTable {
public:
	int pi;
	HashTable *next;
	HashTable() {
		next = NULL;
	}
};
class HashTable *hashtable
;
int n, k; //奶牛数,特征数
int f
[K]; 
int sum
[K]; // sum[i][j]表示从f[1][j]到f[i][j]的第j个数字之和
int c
[K];   // c[i][y] = sum[i][y] - sum[i][0]
int maxlen;

bool cmp(int i, int j)
{
	for (int m = 0; m < k; ++m)
		if (c[i][m] != c[j][m])
			return false;
	return true;
}

void Hash(int i)
{
	int key = 0;
	for (int j = 1; j < k; ++j) {
		key += c[i][j] * j;
	}
	key = abs(key) % prime;
	
	if (!hashtable[key]) {
		hashtable[key] = new class HashTable;
		hashtable[key]->pi = i;
	} else { // key冲突
		class HashTable *ph = hashtable[key];
		if (cmp(ph->pi, i)) { // 看c[][]与当前c[i][]是否相等
			if (i - (ph->pi) > maxlen) {
				maxlen = i - (ph->pi);
			} // 因为pi和i对应列数字相等,且pi地址必定比i小,因此不要保存i
			return;
		} else {
			while (ph->next) { // 看key冲突的从第二个开始与c[i][]是否相等
				if (cmp(ph->next->pi, i)) {
					if (i - (ph->next->pi) > maxlen) {
						maxlen = i - (ph->next->pi);
					} // 同样不需保存i
					return;
				}
				ph = ph->next;
			}

			//key冲突但c[][]不全相同,需要保存i
			class HashTable * tmp = new class HashTable;
			tmp->pi = i;
			ph->next = tmp;
		}
	}
}

int main()
{
	//freopen("temp.txt", "r", stdin);
	while (cin >> n >> k) {
		maxlen = 0;
		memset(hashtable, 0, sizeof(hashtable));
		for (int i = 0; i < k; ++i) {
			sum[0][i] = 0;
			c[0][i] = 0;
		}
		Hash(0);
		int num;
		for (int i = 1; i <= n; ++i) {
			cin >> num;
			for (int j = 0; j < k; ++j) {
				f[i][j] = num % 2;
				num /= 2;
				sum[i][j] = sum[i-1][j] + f[i][j];
				c[i][j] = sum[i][j] - sum[i][0];
			}
			Hash(i);
		}
		cout << maxlen << endl;
	}
	
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: