日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

树的同构模板题(法1.最小表示法+法2.树哈希)

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 树的同构模板题(法1.最小表示法+法2.树哈希) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

樹的同構

  • problem
  • solution
  • code
  • solution
  • code

problem

模板題

solution

Ⅰ. 最小表示法

將樹轉化為 0/10/10/1 括號序列:從根開始 dfs\text{dfs}dfs000 就往下遍歷一個兒子,111 就返回,構成一個 2×n2\times n2×n 的括號序列。

顯然,括號序列與樹的形態是唯一對應的。

  • 有根樹
    • 若兒子遍歷順序是固定的。顯然括號序列只有唯一一種。
    • 若兒子遍歷順序不固定。就會有多種合法的括號序列,不妨欽定字典序最小的為這棵樹的括號序列,這個特殊的括號序列有單獨的名稱:最小表示

顯然,兩棵有根樹的最小表示相同是同構的充要條件

具體實現:遞歸地構造,對于點 uuu,先把兒子 vvv 的括號序列都處理出來后,按照兒子的字典序從小到大排序,然后順次接起來。在這個拼接的括號序列外面用 000(進入 uuu 子樹求解)111(完成 uuu 子樹內的遍歷) “包起來”就表示把 uuu 子樹遍歷完然后返回上一層的最小表示了。

時間復雜度為 O(n2)O(n^2)O(n2)。最壞情況為鏈。

因為括號序列肯定是用字符串 string\text{string}string 類型儲存。

那么 f[u]+=f[v]f[u]+=f[v]f[u]+=f[v] 這一句話的操作復雜度其實是 O(len)O(len)O(len) 的。

  • 無根樹

比較暴力的想法就是對于每個點都當作根,做一遍 dfs\text{dfs}dfs。時間復雜度為 O(n3)O(n^3)O(n3)

對于本題而言,又有 mmm 棵樹,時間復雜度就是 O(n3m)O(n^3m)O(n3m) 的。

實際上,最小表示法就是為了定義一個規則,讓一棵樹擁有唯一的括號序列。如果喜歡最大表示法也是可以的。

所以可以對無根樹找一個特殊的規則,來區別不同構的樹。

這里我們選擇重心為根時的括號序列當作無根樹的括號序列代表。

兩個重心的話就取字典序較小的。

時間復雜度就降為 O(n2m)O(n^2m)O(n2m)

code

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 55 int n, m, Max, cnt; string Min; struct node { int to, nxt; }E[maxn << 1]; int head[maxn], siz[maxn], MaxSiz[maxn]; string f[maxn], g[maxn], mp[maxn];void init() {memset( head, -1, sizeof( head ) );memset( MaxSiz, 0, sizeof( MaxSiz ) );cnt = 0; Max = n; Min = "1"; }void addedge( int u, int v ) {E[cnt] = { v, head[u] };head[u] = cnt ++; }void dfs1( int u, int fa ) {siz[u] = 1;for( int i = head[u];~ i;i = E[i].nxt ) {int v = E[i].to;if( v == fa ) continue;dfs1( v, u );siz[u] += siz[v];MaxSiz[u] = max( MaxSiz[u], siz[v] );}MaxSiz[u] = max( MaxSiz[u], n - siz[u] );Max = min( Max, MaxSiz[u] ); }void dfs2( int u, int fa ) {f[u] = "0";for( int i = head[u];~ i;i = E[i].nxt )if( E[i].to ^ fa ) dfs2( E[i].to, u );int tot = 0;for( int i = head[u];~ i;i = E[i].nxt )if( E[i].to ^ fa ) g[++ tot] = f[E[i].to];sort( g + 1, g + tot + 1 );for( int i = 1;i <= tot;i ++ ) f[u] += g[i];f[u] += "1"; }int main() {scanf( "%d", &m );for( int j = 1;j <= m;j ++ ) {scanf( "%d", &n );init();for( int i = 1, x;i <= n;i ++ ) {scanf( "%d", &x );if( x ) addedge( x, i ), addedge( i, x );}dfs1( 1, 0 );for( int i = 1;i <= n;i ++ )if( MaxSiz[i] == Max ) {dfs2( i, 0 );Min = min( Min, f[i] );}mp[j] = Min;for( int i = 1;i <= j;i ++ )if( mp[i] == mp[j] ) {printf( "%d\n", i );break;}}return 0; }

solution

Ⅱ . 樹哈希

多項式哈希,即 [1,r][1,r][1,r] 的哈希值減去 r?l+1r-l+1r?l+1 乘上 [1,l][1,l][1,l] 的哈希值。

同理,有根樹且兒子有順序,哈希就是一一對應,正確的。

如果有根樹且兒子沒順序,就按照兒子的哈希值排序后,再哈希。

有根樹擴展到無根樹也是尋找重心。

得出哈希值后暴力比較即可。

時間復雜度為 O(nmlog?n)O(nm\log n)O(nmlogn),瓶頸在于排序。(如果你不喜歡 log?\loglog,基排就行)

其實樹哈希就是沒有最小表示法的字符串相關操作帶來的巨大復雜度而已。

哈希唯一的缺點就是會沖突,不能保證一定穩定,但也不至于很容易就被卡掉。

code

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define int long long #define mod 1019260817 #define base 19491001 #define maxn 55 struct node { int to, nxt; }E[maxn << 1]; pair < int, int > f[maxn], g[maxn]; int Pow[maxn], Hash[maxn], head[maxn], siz[maxn], MaxSiz[maxn], dep[maxn]; int n, m, cnt, rt1, rt2, Max;void addedge( int u, int v ) {E[cnt] = { v, head[u] };head[u] = cnt ++; }void dfs1( int u, int fa ) {siz[u] = 1;for( int i = head[u];~ i;i = E[i].nxt ) {int v = E[i].to;if( v == fa ) continue;dfs1( v, u );siz[u] += siz[v];MaxSiz[u] = max( MaxSiz[u], siz[v] );}MaxSiz[u] = max( MaxSiz[u], n - siz[u] );if( MaxSiz[u] < Max ) Max = MaxSiz[u], rt1 = u, rt2 = 0;else if( MaxSiz[u] == Max ) rt2 = u; }void dfs2( int u, int fa ) {Hash[u] = Pow[siz[u] = 1] * dep[u] % mod;for( int i = head[u];~ i;i = E[i].nxt ) if( E[i].to ^ fa ) dep[E[i].to] = dep[u] + 1, dfs2( E[i].to, u );int tot = 0;for( int i = head[u];~ i;i = E[i].nxt )if( E[i].to ^ fa ) g[++ tot] = { Hash[E[i].to], siz[E[i].to] };sort( g + 1, g + tot + 1 );for( int i = 1;i <= tot;i ++ )Hash[u] = ( Hash[u] + g[i].first * Pow[siz[u]] ) % mod, siz[u] += g[i].second; }signed main() {Pow[0] = 1;for( int i = 1;i < maxn;i ++ ) Pow[i] = Pow[i - 1] * base % mod;scanf( "%lld", &m );for( int k = 1;k <= m;k ++ ) {memset( MaxSiz, 0, sizeof( MaxSiz ) );memset( head, -1, sizeof( head ) );cnt = 0; Max = mod;scanf( "%lld", &n );for( int i = 1, x;i <= n;i ++ ) {scanf( "%lld", &x );if( x ) addedge( i, x ), addedge( x, i );}dfs1( 1, 0 );dep[rt1] = 1;dfs2( rt1, 0 );f[k].first = Hash[rt1];if( ! rt2 ) goto pass;dep[rt2] = 1;dfs2( rt2, 0 );f[k].second = Hash[rt2];if( f[k].first > f[k].second ) swap( f[k].first, f[k].second );pass : ; }for( int i = 1;i <= m;i ++ )for( int j = 1;j <= i;j ++ )if( f[i] == f[j] ) { printf( "%lld\n", j ); break; }return 0; }

總結

以上是生活随笔為你收集整理的树的同构模板题(法1.最小表示法+法2.树哈希)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产睡熟迷奷系列精品视频 | 午夜精品一区二区三区在线播放 | 欧美精品一区二区三区久久久 | 自拍偷拍色综合 | 91精产国品一二三 | 看黄色大片 | wwwww在线观看 | 天堂av资源网 | 九九热在线精品 | 91福利视频免费观看 | 国产精品福利片 | 综合久久久久久久 | 色综综 | 巨大乳の揉んで乳榨り奶水 | 中文字幕av专区dvd | 国自产拍偷拍精品啪啪一区二区 | av无码精品一区二区三区宅噜噜 | 久久久久久亚洲精品中文字幕 | 久久综合一区二区三区 | 九九热av | 亚洲有吗在线 | 国产午夜不卡 | 欧美日韩女优 | 久久精品在线视频 | 亚洲精品粉嫩小泬 | 青草精品视频 | 久久免费精彩视频 | 国产呦小j女精品视频 | wwwav视频 | 清清草视频| 在线中文字幕播放 | 91色影院 | 在线免费观看成人 | 5个黑人躁我一个视频 | avtt亚洲| 777奇米视频 | 在线h片 | 亚洲综人 | 午夜视频在线观看国产 | 免费看av的网址 | bt天堂av | 日日骚视频 | 粗大黑人巨茎大战欧美成人 | 最新中文字幕在线观看 | 日本高清不卡在线观看 | 欧美啪啪小视频 | 国产午夜免费福利 | 亚洲av无码一区二区乱子伦as | 日韩精品人妻一区二区中文字幕 | 亚洲精品无码不卡在线播he | 日韩黄色免费观看 | 美女福利在线视频 | 亚洲丝袜在线观看 | 香蕉视频网站在线 | 亚洲国产精品18久久久久久 | 亚洲乱码精品久久久久 | 欧美黄色a| 亚洲23p| 17c一起操 | 国产日韩高清在线 | 国产欧美久久久久 | 亚洲 欧美 日韩 综合 | 超碰在线色 | 国产精品1| 亚洲av成人无码一二三在线观看 | 鲁丝一区二区三区 | 国产成人av一区 | 麻豆视频免费在线观看 | 日韩精品短片 | 国产成人区 | 午夜黄色大片 | 国产精品久久久久久久久岛 | 91蝌蚪视频在线 | 伊人av影院| 久久午夜鲁丝 | 伊人一区二区三区 | 精品色哟哟 | 亚洲精品欧美精品 | 亚洲高清自拍 | 成人做受黄大片 | 日美毛片 | 黄色激情视频在线观看 | 在线观看成年人网站 | 欧美一级性片 | 香蕉视频网站入口 | 伊人网av在线| 中文字字幕第183页 欧美特级一级片 | 国产tv在线观看 | 国产 欧美 自拍 | 亚洲aⅴ网站 | 欧美最猛黑人xxxx黑人猛交 | 亚洲精品免费网站 | 天天插天天射天天干 | 玖玖精品 | 亚洲精品久久久久久久久 | 免费黄在线看 | 成年人国产精品 | 午夜精品久久久久久久99热浪潮 | 国产精品电影网 |