二哥的内存

        疯了疯了抓狂,在OJ上做去年的一道机考题,提交了25次,其中超过时间限制14次,答案错误4次,运行时错误4次,终于赢下了这场攻坚战,并从中提炼出一条朴素的真理:cout是很慢的……

        题目链接:http://acm.sjtu.edu.cn/OnlineJudge/problem/1053

        问题描述如下:一个规模为100000 * 100000的稀疏矩阵,其中至多10000个位置被赋了值,其余位置上均为零。对矩阵进行以下三种操作:交换两行的值;交换两列的值;询问矩阵当前某个位置上的值。

        据某大腿指点,我们可以利用两个数组建立当前行列与初始行列的映射关系。例如,用int xx[100000]表示当前某行在初始时刻的位置,xx[i]被赋初值i,需要交换x行和y行时,只需交换xx[x]和xx[y]。因此,xx[i] = j,yy[k] = l,表示当前(i, k) 位置对应于初始时刻的(j, l)位置。这样避免了直接交换矩阵中的元素,将交换的时间复杂度降低为常数。

        在查询中采用哈希的办法。将矩阵元素的下标x,y映射成整数pos,分别在坐标类数组和一个整型数组的pos位置上储存坐标和值。当需要查询时,求出x,y对应的pos,查看坐标类数组的pos位置,若为查询的坐标,则找到这一项,输出其值;否则输出零。哈希表碰撞的解决直接用了线性探测法。源代码见下:

// 1053 Erge's memory
#include<iostream>
#include<stdio.h> 
const int HASH_MAX = 233333;
using namespace std;
 
struct coordinate{
	int x;
	int y;
	
	coordinate(){
		x = -1;
		y = -1;
	}
};
 
coordinate cohash[HASH_MAX];
int valhash[HASH_MAX] = {0};
 
int main(){
	int xx[100000], yy[100000], i, j, n, m;	
	
	for (i = 0; i <= 99999; i++) xx[i] = yy[i] = i;
	
	cin >> n;
	int z;
	unsigned int x, y;
	for (i = 1; i <= n; i++){
		//cin >> x >> y >> z;
		scanf("%d%d%d", &x, &y, &z);
		int pos = x * y % HASH_MAX;
		while (cohash[pos].x != -1) pos = (pos + 1) % HASH_MAX;
		cohash[pos].x = x;
		cohash[pos].y = y;
		valhash[pos] = z;
	}
	
	cin >> m;
	for (i = 1; i <= m; i++){
		//cin >> j >> x >> y;
		scanf("%d%d%d", &j, &x, &y);
		int tmp, pos;
		switch(j){
			case 0:
				// Exchange Row x with Row y
				tmp = xx[x];
				xx[x] = xx[y];
				xx[y] = tmp;
				break;
			case 1:
				// Exchange Column x with Column y
				tmp = yy[x];
				yy[x] = yy[y];
				yy[y] = tmp;
				break;
			case 2:
				// Find value in position (x, y)
				x = xx[x];
				y = yy[y];
				pos = x * y % HASH_MAX;
				while (!(cohash[pos].x == x && cohash[pos].y == y) && cohash[pos].x != -1)
				    pos = (pos + 1) % HASH_MAX;
				if (cohash[pos].x == -1) printf("0\n");
				else printf("%d\n", valhash[pos]);
				break;
		}
	}
	
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值