概念
啟發式演算法是基於人類的經驗和直觀感覺,對一些演算法的優化。
作用可以啟發式合併更加高階的資料結構,如 \(heap,~set,~splays\) 等
複雜度計算
每次把個數少的合併到個數多的?複雜度 \(o(min(m1,m2))\)
可是我們注意到,每次合併後個數為合併前少的部分的個數的兩倍以上,每個元素最多合併 \(logm\) 次,總複雜度 \(o(mlogm)\) 。
當合併 \(heap,~set,~splays\) 等,複雜度 \(o(mlog2m)\)(作者太弱,不會證明)
例題1[hnoi2009] 夢幻布丁
思路對於每乙個顏色,建一條鍊錶。然後染色就是把鏈短的合併到鏈長的。
需要注意細節,如果把2染成3,但2的鏈比3的長,就需要把3的合併到2上。但是現在本應屬於3的鏈在2上,就需要記乙個該顏色的鏈現在在哪個顏色上,即是**中的 \(now\) 陣列。
**
#include#define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
#define per(i, a, b) for (register int i=(a); i>=(b); --i)
using namespace std;
void swap(int &x, int &y)
const int n=1000005;
int head[n], nxt[n], col[n], now[n], cnt[n], st[n], ans;
inline int read()
void merge(int x, int y)
for (int i=head[x]; i; i=nxt[i]) col[i]=y;
nxt[st[x]]=head[y]; head[y]=head[x];
head[x]=st[x]=cnt[x]=0;
}int main()
rep(i, 1, m)
}return 0;
}
例題2
[十二省聯考2019]春節十二響
思路考慮一條鏈,顯然你是把兩個鏈分別的最大值放在一起,次大值放在一起,等等
那麼如果有多個鏈呢?你就把第乙個鏈和第二個鏈按上面的操作,得到的新的結果再和第三個鏈合併...
**
#include#include#include#include#include#define ll long long
using namespace std;
const int maxn=2e5+5;
int a[maxn],id[maxn],tot,tp[maxn];
priority_queueq[maxn];
inline int read()
while(isdigit(ch))
return x*f;
}struct edgee[maxn<<1];
int head[maxn],cnt;
void add(int u,int v)
inline void dfs(int now,int fa)
for(int j=1;j<=size;j++) q[id[now]].push(tp[j]);
} q[id[now]].push(a[now]);
}int main()
dfs(1,0);
ll ans=0;
while(q[id[1]].size()) ans+=q[id[1]].top(),q[id[1]].pop();
printf("%lld",ans);
return 0;
}
啟發式合併
啟發式合併 暴力合併 將兩個資料結構合併,只需要將小的資料結構中的元素乙個乙個的插入大的資料結構o n o n o n 如果題目只有插入操作沒有 總o n logn o nlogn o nlog n 因為每次合併,所有資料結構總大小為n,設兩個資料結構大小為a,b a b a,b a b a,b a...
啟發式合併
includeconst int n 5e5 5 int f n d n r n p n int find int i int unionn int i,int j int main 並查集 按秩啟發式合併 bzoj4668 冷戰 題目大意 給出n個軍工廠和m 個操作,操作分為兩類 0 u v,這次...
啟發式合併
啟發式合併本質上是一種優化的暴力,可用於擁有穩定結構的資料結構。考慮夢幻布丁 hnoi2009 顯然的暴力思路是用鍊錶維護每種顏色的位置,然後每次修改的時候暴力合併兩條鏈。不難證明,這樣的最壞時間複雜度將達到 o n 2 不能接受。可以觀察到,合併的時間複雜度只與被合併的鏈長度有關,所以可以想到優化...