題目:
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 21Sample Output:
1 13 12 21 33 34 38 27 22 32
分析:上一個星期去幹別的了,當時剩了這最後一道題了,當時一直想不來,實在是無奈,所以過了一個星期纔回來繼續把它完成,在聽完姥姥的講解後,的確是很需要思考和分析能力的一道題。
題目的意思很簡單,仔細閱讀後(雖然也花了蠻久的,英語太差,怪我咯),還是能明白題意的,就是hash表的逆過程,也就是給出hash表序列和hash函數,需要你求出原始的序列,需要注意的是當有多個時,小的在前面(the smallest number is always taken.)。
這道題的代碼不是自己寫的,相似度很高,自己還需修行,太菜呀。
解題思路:
1.把Hash表的序列保存到數組中(我的習慣使用了vector,數組也一樣的)
2.計算入度,即衝突次數,並建立有向圖,把下標當頂點。從Key%N 到 當前下標 - 1的頂點都指向當前下標,因爲這些點都影響當前頂點。
3.拓撲排序,把度爲0的頂點放入最小堆中,STL可以用優先隊列。(STL真的是很好的工具)
4.找出度爲0且值最小的頂點,掃描與該點相連的頂點,入度 - 1,如果入度變0,則加入最小堆或者優先隊列。
5.取最小堆頂點或者取隊列首元素的時候,把該頂點的Key存入數組,當然你也可以直接輸出。
代碼:
#include<iostream>
#include<vector>
#include<queue>
#include<functional>
using namespace std;
int main()
{
int N;
cin >> N; //輸入哈希表的大小
int *Hash = new int[N]; //Hash數組
int *Degree = new int[N]; //入度數組
vector<vector<int>> G(N); //無向圖 二維vector容器
vector<int> Ans; //輸出序列
//輸入hash序列
for (int i = 0; i < N; i++){
cin >> Hash[i];
if (Hash[i] > 0)
Degree[i] = 0;
else
Degree[i] = -1; //如果小於0,入度記爲-1,表示沒有元素
}
//計算入度並建立無向圖
for (int i = 0; i < N; i++){
if (Hash[i] < 0)
continue;
int curPos = i; //當前座標
int hashPos = Hash[i] % N; //Hash後的座標
Degree[i] = (curPos - hashPos + N) % N; //計算入度,也就是衝突的次數
for (int j = 0; j < Degree[i]; j++)
G[(hashPos + j + N) % N].push_back(i);
}
//拓撲排序
typedef pair<int, int> PAIR;
priority_queue<PAIR, vector< PAIR >, greater< PAIR >> q; //優先隊列
for (int i = 0; i < N; i++){
if (Degree[i] == 0){
q.push(PAIR(Hash[i], i));
}
}
while (!q.empty())
{
PAIR p = q.top(); //每次取出當前入度爲0的頂點中Key最小的
int V = p.second; //second爲頂點
Ans.push_back(p.first); //first爲該頂點的Key
q.pop();
for (int i = 0; i < G[V].size(); i++) //掃描關聯頂點,入度處理
if (--Degree[G[V][i]] == 0)
q.push(PAIR(Hash[G[V][i]], G[V][i]));
}
//輸出
cout << Ans[0];
for (int i = 1; i < Ans.size(); i++)
cout << ' ' << Ans[i];
return 0;
}
==================================================================================================================================
總結:最後一道題也結束了,通過這門課,pat的這些題,真的學到了很多東西,也發現了自己真的好菜呀,不過所有人一開始都是不懂得嘛,慢慢學。當然,同時發現,自己需要學的東西還有很多,真的好難呀,前面的這些題,真正自己做出來的真的沒幾個,很多都是通過查閱,google,百度呀出來的,所以還要好好修行,但也正是查閱過程中,感覺還是學會很多的知識的,比如STL,這真的是一個強大的工具,當然這個也不是萬能的哈,有些時候還是要自己寫最基礎的算法的。 ^_^