P3405 [USACO16DEC]Cities and States S 題解
阿新 • • 發佈:2021-08-07
理解與感悟
1、字串Hash,其實是儲存的字串的整數對映值。這個整數對映的計算有不同的方法,一般採用模擬N進位制的方式獲取。N通常是大於127,就是ASCII的字元上限,如果只有大寫或小寫,也可以使用26.
2、模後拉鍊的辦法很常用,學習其思想。
3、STL真是封裝的太棒了,不用自己費勁。
一、字串Hash模板法
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> PII; const int MOD = 23333; //需要模的常數,一般為質數 int n; string a, b; vector<PII> linker[MOD + 10]; int ans; //極限值是20000*20000=400000000,是不會爆int的,這個分析很棒~ //算出兩個字串拼在一起的Hash值 int getHash(string a, string b) { //擴充套件閱讀 秦九韶演算法 //https://haokan.baidu.com/v?pd=wisenatural&vid=14006885485484083472 //26進位制的意思,當然,這個26也可以是大於26的任意值 return a[0] - 'A' + (a[1] - 'A') * 26 + (b[0] - 'A') * 26 * 26 + (b[1] - 'A') * 26 * 26 * 26; } //插入到連結串列 void insert(int x) { for (int i = 0; i < linker[x % MOD].size(); i++) if (linker[x % MOD][i].first == x) { linker[x % MOD][i].second++; return; //此處,書上的程式碼有錯誤 } linker[x % MOD].push_back({x, 1}); } //查詢Hash值等於x的個數是多少 int find(int x) { for (int i = 0; i < linker[x % MOD].size(); i++) if (linker[x % MOD][i].first == x) return linker[x % MOD][i].second; return 0; } int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> a >> b; //如果反過來掉過去都一樣,就是自己和自己,不是特殊的一對,只有不一樣的才可能是特殊的一對 if (a.substr(0, 2) != b.substr(0, 2)) { //將a和b的hash計算出來,並存入Hash表中 insert(getHash(a, b));//如果不存在,則建立,值為1;如果存在,則值++ //計算一下b,a的Hash值是多少,查詢一下b,a的Hash值個數,累加 ans += find(getHash(b, a)); } } //輸出結果 cout << ans << endl; return 0; }
二、STL大法
#include <bits/stdc++.h> using namespace std; int n; string a, b; int ans; //極限值是20000*20000=400000000,是不會爆int的 unordered_map<string, int> _map; int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> a >> b; //如果反過來掉過去都一樣,就不用計算 string a1 = a.substr(0, 2), b1 = b.substr(0, 2); if (a1 != b1) { _map[a1 + b1]++; ans += _map[b1 + a1]; } } //輸出結果 cout << ans << endl; return 0; }