AcWing 137 雪花雪花雪花

2021-09-22 20:19:05 字數 3124 閱讀 9290

題目描述:

有n片雪花,每片雪花由六個角組成,每個角都有長度。第i片雪花六個角的長度從某個角開始順時針依次記為ai,1,ai,2,…,ai,6。

因為雪花的形狀是封閉的環形,所以從任何乙個角開始順時針或逆時針往後記錄長度,得到的六元組都代表形狀相同的雪花。

例如ai,1,ai,2,…,ai,6和ai,2,ai,3,…,ai,6,ai,1就是形狀相同的雪花。ai,1,ai,2,…,ai,6和ai,6,ai,5,…,ai,1也是形狀相同的雪花。

我們稱兩片雪花形狀相同,當且僅當它們各自從某一角開始順時針或逆時針記錄長度,能得到兩個相同的六元組。求這n片雪花中是否存在兩片形狀相同的雪花。

輸入格式

第一行輸入乙個整數n,代表雪花的數量。接下來n行,每行描述一片雪花。每行包含6個整數,分別代表雪花的六個角的長度(這六個數即為從雪花的隨機乙個角順時針或逆時針記錄長度得到)。同行數值之間,用空格隔開。

輸出格式

如果不存在兩片形狀相同的雪花,則輸出:no two snowflakes are alike.

如果存在兩片形狀相同的雪花,則輸出:twin snowflakes found.

資料範圍

1≤n≤100000,

0≤ai,j<10000000

輸入樣例:

2

1 2 3 4 5 6

4 3 2 1 6 5

輸出樣例:

twin snowflakes found.
分析:

做這題前看別人說時間空間卡的很緊,所以遲遲沒有下手,結果用笨辦法一股腦刷刷寫完,竟然一遍ac了,也覺得很驚奇。

在介紹本題的解法之前,先引入字串的最小表示法的概念。我們需要求乙個字串的迴圈同構體中最小字典序的那個。比如bcda的迴圈同構體有bcda,cdab,dabc,abcd,其中最小表示法是abcd。

那麼如何高效的求解字串的最小表示法呢?顯然,暴力求解的話就是依次列舉字串的起點,再與其他位置作為起點的字串一一對比,總的時間複雜度是o(n ^2)。以abcdabcebdd為例詳細描述下暴力做法的過程。

定義雙指標i = 0,j = 1,首先a < b所以字串的第二個位置不會作為最優解字串的開頭,同理,後面的cd也都不會作為字串的開頭,直到j = 4匹配到了另乙個a,於是i,j均右移,發現後面的bc也都相等,繼續右移,直至遇見了d < e,所以abce不可能是最小表示法的字首,然後j又回到下標為5的位置,i也回到開頭,a < b,繼續比較。

上面的匹配過程可以採用類似於kmp演算法的思想來優化,一句話概括就是遇見不可能匹配的字首就快速跳過,不再進行比較。在比較到abcd和abce時,發現不匹配了,於是i指標還是回到起點,而j指標不必再回到abce中的b位置進行下一次匹配,因為一旦abce喪失了作為字串真字首的資格,其子串也都失去了作為字首的資格。比如說bce有作為字首的資格,則由之前的比較可知i指標指向的乙個字首bcd是比該字首小的,不論是abce的哪個子串,在abcd中都能夠找到字典序小於它的子串。所以:

abcdabcebdd

abcebddabcd

兩個迴圈同構體在d和e的位置失配時,第乙個指標重新回到下標為0的位置,而第二個指標不需要在從下標為0的位置的後乙個位置再進行比較,既然abce都失去了字首的資格,那麼第二個指標從第五個字元b再次開始比較即可,如此,指標便可快速右移。

總結下最小表示法的求解思路:

i,j分別指向待匹配兩個字串的首位置,k表示已匹配的長度,一旦當前的位置匹配,則k++,否則,字典序較大的那個字串的指標則要右移k + 1位才能再次進行比較。最小表示法**如下:

#include #include #include using namespace std;

int findmin(string s)

else

if (i == j) j++;

} return min(i, j);

}int main()

return 0;

}

說完了最小表示法,正式說下本題解題思路。本題需要判斷雪花是否相同,只要兩片雪花的六個角的最小表示法相同,我們就可以斷定這兩片雪花完全相同,所不同的是:上面介紹的最小表示法只能自左往右迴圈,而本題可以自右向左迴圈,只需讀入時備份一下逆置的陣列,然後僅保留兩個陣列的最小表示即可。

至於如何剪枝來避免不必要的比較,可以使用簡單的雜湊來解決。我們知道,兩片雪花相同的充要條件就是六個角最小表示法相同,如果對任意兩片雪花的六個角求和,則當兩片雪花的六角和不等時,他們一定不相同。考慮到本題的資料範圍,在求和對映時需要取模,一般取接近於最大範圍的最大的素數,我這裡取的是9999991。

綜上所述:本題的主要思路就是,先對所有雪花都雜湊對映到某個值,只有兩片雪花雜湊後的值相等時他們才可能相等,再比較他們的最小表示法即可驗證。

#include #include #include using namespace std;

typedef long long ll;

const int maxn = 100005;

int a[maxn][6],b[maxn][6],p[maxn];

unordered_map> m;

bool cmp(int *a,int *b)

return true;

}bool issame(int *a,int *b)

return true;

}void getmin(int *a)

else

if(i == j) j++;

}int s = min(i,j);

k = 0;

int b[6];

while(k < 6) b[k++] = a[(s++) % 6];

for(int i = 0;i < 6;i++) a[i] = b[i];

}void getunique(int *a,int *b)

}int gethash(int *a)

int main()

getunique(a[i],b[i]);

m[gethash(a[i])].push_back(i);

}for(auto x : m)}}

}}

cout<<"no two snowflakes are alike."

}

Acwing 137 雪花雪花雪花

有n片雪花,每片雪花由六個角組成,每個角都有長度。第i片雪花六個角的長度從某個角開始順時針依次記為ai,1,ai,2,ai,6ai,1,ai,2,ai,6。因為雪花的形狀是封閉的環形,所以從任何乙個角開始順時針或逆時針往後記錄長度,得到的六元組都代表形狀相同的雪花。例如ai,1,ai,2,ai,6a...

AcWing 137 雪花雪花雪花 初探hash

題目鏈結 本題的資料範圍顯然不能把所有陣列乙個乙個對比,可以建立乙個雜湊表,不同的h x 代表不同的雜湊值,雜湊值衝突的陣列就存在同乙個h x 開頭的煉表裡,然後根據雜湊值來對比對應的字串,減少重複比較。const int maxn 1e5 10 int a 10 snow maxn 6 h max...

演算法高階指南 Acwing 137 雪花雪花雪花

有n片雪花,每片雪花由六個角組成,每個角都有長度。第i片雪花六個角的長度從某個角開始順時針依次記為ai,1,ai,2,ai,6。因為雪花的形狀是封閉的環形,所以從任何乙個角開始順時針或逆時針往後記錄長度,得到的六元組都代表形狀相同的雪花。例如ai,1,ai,2,ai,6和ai,2,ai,3,ai,6...