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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

「日常训练」 Genghis Khan the Conqueror(HDU-4126)

發(fā)布時(shí)間:2023/12/18 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 「日常训练」 Genghis Khan the Conqueror(HDU-4126) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題意

給定\(n\)個(gè)點(diǎn)和\(m\)條無(wú)向邊(\(n\le 3000\)),需要將這\(n\)個(gè)點(diǎn)連通。但是有\(Q\)次(\(Q\le 10^4\))等概率的破壞,每次破壞會(huì)把\(m\)條邊中的某條邊的權(quán)值增大某個(gè)值,求\(Q\)次破壞每次將\(n\)個(gè)點(diǎn)連通的代價(jià)的期望?(全題的數(shù)據(jù)范圍在int內(nèi)可以過(guò))

分析

這題是真的牛逼,我看了七八個(gè)博客都沒(méi)看太明白,大多數(shù)人都沒(méi)講在點(diǎn)子上,但是還是有幾篇博客不錯(cuò)的,參考如下:
參考A:https://blog.csdn.net/u014664226/article/details/49333081
參考B:https://blog.csdn.net/Anxdada/article/details/81086041
參考C:https://blog.csdn.net/ramay7/article/details/52236040 (這個(gè)是最好的,強(qiáng)烈推薦)
參考D:https://blog.csdn.net/gatevin/article/details/47042021 (有一些“實(shí)質(zhì)上”的東西)

接下來(lái)說(shuō)說(shuō)我綜合這些參考后自己對(duì)這題的理解與做法。

求期望的意思是,將每次破壞后的最小生成樹(shù)的代價(jià)累加除以\(Q\)。然后我們仔細(xì)思考一下這個(gè)破壞。首先,如果更改發(fā)生在不是最小生成樹(shù)上的邊上,那么答案是不需要改變的。重點(diǎn)是改變發(fā)生在這棵生成樹(shù)上的邊中的情況下。此時(shí)這棵最小生成樹(shù)會(huì)分成兩棵樹(shù)。顯然地,新圖的最小生成樹(shù)一定包含這兩棵樹(shù)上的所有邊。問(wèn)題于是轉(zhuǎn)化為原來(lái)的最小生成樹(shù)被切成兩棵樹(shù)之后,如何選擇權(quán)值最小的一條邊將兩棵樹(shù)連通。
這里因此運(yùn)用了樹(shù)形dp。這里比較精彩:
我們記\(dp[i][j]\)是切斷\((i,j)\)邊后,i與j兩個(gè)所在點(diǎn)的集合間的最短距離。但是我們不去直接這么搜索,而是去搜索i所在樹(shù)的樹(shù)根與j所在子樹(shù)的每一個(gè)點(diǎn)的最短距離。于是我們將每個(gè)點(diǎn)當(dāng)作樹(shù)根進(jìn)行DFS,在更新(搜索)時(shí),我們用j所在子樹(shù)所有點(diǎn)同root的直接距離更新掉dp數(shù)組,并有意歸避掉\((i,j)\)邊。可以想見(jiàn),當(dāng)?shù)?span id="ozvdkddzhkzd" class="math inline">\(i\)輪更新完成,dp中一定保存了第1個(gè)到第\(i\)個(gè)root到他們相關(guān)點(diǎn)的最短距離。那么對(duì)每個(gè)點(diǎn)都dp過(guò)后,最后dp數(shù)組里面一定保存的就是我們要的東西了。

最后對(duì)每個(gè)查詢(xún)做修正就可以了,具體見(jiàn)代碼。真實(shí)樹(shù)形dp+最小生成樹(shù)好題,就是做的頭疼,哈哈。

代碼

/* ACM Code written by Sam X or his teammates.* Filename: hdu4126.cpp* Date: 2018-11-18*/#include <bits/stdc++.h>#define INF 0x3f3f3f3f #define PB emplace_back #define MP make_pair #define fi first #define se second #define rep(i,a,b) for(repType i=(a); i<=(b); ++i) #define per(i,a,b) for(repType i=(a); i>=(b); --i) #define ZERO(x) memset(x, 0, sizeof(x)) #define MS(x,y) memset(x, y, sizeof(x)) #define ALL(x) (x).begin(), (x).end()#define QUICKIO \ios::sync_with_stdio(false); \cin.tie(0); \cout.tie(0); #define DEBUG(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)using namespace std; using pi=pair<int,int>; using repType=int; using ll=long long; using ld=long double; using ull=unsigned long long;int n,m;struct Edge {int u,v,w;Edge() {}Edge(int _u,int _v, int _w):u(_u), v(_v), w(_w) {}bool operator < (const Edge& rhs) const{if(w==rhs.w){return u<rhs.u;}else return w<rhs.w;} }; const int MAXN=3005; vector<Edge> edges; int mat[MAXN][MAXN]; int used[MAXN][MAXN];int edges_ord[18000005]; int pa[MAXN]; vector<Edge> nedges; vector<int> nG[MAXN]; inline void nadd_edge(int u,int v,int w) {nedges.PB(u,v,w);nG[u].PB(int(nedges.size())-1); } int find_pa(int x) {return pa[x]==x?x:pa[x]=find_pa(pa[x]); } inline void union_pa(int x,int y) {int fx=find_pa(x),fy=find_pa(y);if(fx!=fy) pa[fx]=fy; } inline int kruskal() {int ret=0;iota(pa,pa+n,0);sort(ALL(edges));rep(i,0,edges.size()-1){int u=edges[i].u,v=edges[i].v,w=edges[i].w;if(find_pa(u)!=find_pa(v)){union_pa(u,v);ret+=w;used[u][v]=used[v][u]=w;nadd_edge(u,v,w);nadd_edge(v,u,w);}}return ret; }int dp[MAXN][MAXN]; int dfs(int root, int now, int pre) {//cout<<root<<" "<<now<<" "<<pre<<endl;int ans=INF;rep(i,0,int(nG[now].size())-1){int& v=nedges[nG[now][i]].v;if(v!=pre){int tmp=dfs(root,v,now);ans=min(ans,tmp);dp[now][v]=dp[v][now]=min(dp[now][v], tmp);}}if(root!=pre && pre!=-1){ans=min(ans, mat[now][root]);}return ans; }inline void init() {edges.clear();nedges.clear();rep(i,0,n-1) nG[i].clear();MS(dp,0x3f);MS(used,-1);MS(mat,0x3f); }int main() {while(scanf("%d%d",&n,&m)==2){if(!n && !m) break;init();rep(i,0,m-1){int u,v,w;scanf("%d%d%d",&u,&v,&w);edges.PB(u,v,w);mat[u][v]=mat[v][u]=w;}int sum=kruskal();rep(i,0,n-1)dfs(i,i,-1);int q;scanf("%d",&q);double ans=0;rep(i,0,q-1){int u,v,w;scanf("%d%d%d",&u,&v,&w);if(used[u][v]!=-1) ans+=sum-used[u][v]+min(dp[u][v], w);else ans+=sum;}printf("%.4lf\n",ans/(1.0*q));}return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/samhx/p/HDU-4126.html

總結(jié)

以上是生活随笔為你收集整理的「日常训练」 Genghis Khan the Conqueror(HDU-4126)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。