Given a hash table of size N, we can define a hash function H(x)=x%N. Suppose that the linear probing is used to solve collisions, we can easily obtain the status of the hash table with a given sequence of input numbers.
However, now you are asked to solve the reversed problem: reconstruct the input sequence from the given status of the hash table. Whenever there are multiple choices, the smallest number is always taken.
Input Specification:
Each input file contains one test case. For each test case, the first line contains a positive integer N (≤1000), which is the size of the hash table. The next line contains N integers, separated by a space. A negative integer represents an empty cell in the hash table. It is guaranteed that all the non-negative integers are distinct in the table.
Output Specification:
For each test case, print a line that contains the input sequence, with the numbers separated by a space. Notice that there must be no extra space at the end of each line.
Sample Input:
11
33 1 13 12 34 38 27 22 32 -1 21
Sample Output:
1 13 12 21 33 34 38 27 22 32
题目大意:给定一串序列,是用哈希函数x%N存入数组中的,其中用线性探测解决冲突。如果是负数,表示该位置没有数字。现在要求这串序列输入的顺序是什么。如果有的数顺序并列,则从小到大输出。(根据数据和哈希值求输入顺序)
分析:如果某个数a的哈希值不是它的当前位置,并且这个哈希值处有数据b的话,说明b是在a前面输入的,这样二者求哈希值的时候,a就会冲突,然后线性探测,就被放到后面去了。
图示:
- 15%5==0,无冲突;
- 10%5==0,冲突了,探测一次,说明15是在10之前被输入的。在图中,用一条有向箭头表示先后关系;
- 7%5==2,无冲突;
- 5%5==0,冲突了,探测三次,说明15、10、7都是在5之前放进去的。
这样就构成了一个有向无环图DAG,所以要用到拓扑排序。
思路:
- 输入数据存入数组a[ ]中,并记录被存入的数字个数,以控制后续的输出格式;
- 根据给出的数据和哈希值构造DAG;
- 拓扑排序输出序列。由于在并列时,要从小到大输出,这里用到优先队列。
ps:
- 在进行建图和入队等操作时,对下标进行操作。我一开始是用的数据进行操作,由于没给数据的范围,而我的maxn又是1000,所以就出现了段错误……
- 题目说的是负数表示没有数字,而我一开始写的是-1表示没有……
- 在入队的时候,由于既要将将下标入队,又要将数据入队(方便输出),所以要用到pair。
代码如下:
#include <iostream>
#include <queue>
#define maxn 1000
using namespace std;
typedef pair<int, int> P;
int n, e[maxn][maxn], indegree[maxn], a[maxn];
void topsort(int cnt)
{
int i;
priority_queue<P, vector<P>, greater<P> >q;/* 最小堆 */
for(i=0; i<n; i++)
if(indegree[i] == 0)
q.push(P(a[i], i));/* 把数据和下标入队 */
int sum = 0;
/* 拓扑排序核心部分 */
while(!q.empty())
{
P x = q.top();
q.pop();
sum++;
if(sum == cnt) cout << x.first << endl;
else cout << x.first << " ";
for(i=0; i<n; i++)
{
if(a[i] >= 0 && e[x.second][i] > 0)
{
if(--indegree[i] == 0)
q.push(P(a[i], i));
}
}
}
}
int main()
{
cin >> n;
int i, j, cnt = 0;
for(i=0; i<n; i++)
{
cin >> a[i];
if(a[i] < 0) indegree[i] = -1;
else
{
cnt++;
indegree[i];
}
}
for(i=0; i<n; i++)
{
if(a[i] >= 0)/* 如果有数字 */
{
for(j=0; (a[i]+j)%n !=i ;j++)/* 计算哈希值和线性探测同时进行 */
{
int pos = (a[i]+j) % n;
e[pos][i] = 1;
indegree[i]++;
}
}
}
topsort(cnt);
return 0;
}
总结
- 在没有给数据范围的时候,对下标进行操作,避免段错误(数组越界等)。
- 第一次用到STL的优先队列和pair容器。
/* 优先队列 */
priority_queue<int>q /* 默认大顶堆 */
priority_queue<int, vector<int>, greater<int> >q;/* 小顶堆 */
priority_queue<int, vector<int>, less<int> >q;/* 大顶堆 */
/* 要注意最后的位置是> >,不是>>,否则会编译错误 */
q.top()/* 在优先队列中,取队首元素不是q.front(),而是q.top() */
/* pair:包含<iostream>头文件就够了 */
pair<int, int>p;/* 可以理解为结构体,用一个变量存两个值 */
p.first;/* 访问p的第一个值 */
p.second;/* 访问p的第二个值 */
- 优先队列和pair结合使用时,优先队列先排first的优先级;first相同时,排second的优先级。