疯了疯了,在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;
}