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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【HDU - 5452】Minimum Cut(树形dp 或 最近公共祖先lca+树上差分,转化tricks,思维)

發(fā)布時(shí)間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【HDU - 5452】Minimum Cut(树形dp 或 最近公共祖先lca+树上差分,转化tricks,思维) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題干:

Given a simple unweighted graph?GG?(an undirected graph containing no loops nor multiple edges) with?nn?nodes and?mm?edges. Let?TT?be a spanning tree of?GG.?
We say that a cut in?GG?respects?TT?if it cuts just one edges of?TT.?

Since love needs good faith and hypocrisy return for only grief, you should find the minimum cut of graph?GG?respecting the given spanning tree?TT.

Input

The input contains several test cases.?
The first line of the input is a single integer?t?(1≤t≤5)t?(1≤t≤5)?which is the number of test cases.?
Then?tt?test cases follow.?

Each test case contains several lines.?
The first line contains two integers?n?(2≤n≤20000)n?(2≤n≤20000)?and?m?(n?1≤m≤200000)m?(n?1≤m≤200000).?
The following?n?1n?1?lines describe the spanning tree?TT?and each of them contains two integers?uu?and?vv?corresponding to an edge.?
Next?m?n+1m?n+1?lines describe the undirected graph?GG?and each of them contains two integers?uu?and?vv?corresponding to an edge which is not in the spanning tree?TT.

Output

For each test case, you should output the minimum cut of graph?GG?respecting the given spanning tree?TT.

Sample Input

1 4 5 1 2 2 3 3 4 1 3 1 4

Sample Output

Case #1: 2

題目大意:

給你一個(gè)圖G,n個(gè)點(diǎn)m條邊,圖中給定一顆生成樹(前n-1條輸入的邊)。問一個(gè)最小割的邊數(shù)量(將圖變成一個(gè)不連通圖),要求需要包含給定生成樹內(nèi)的一條邊。

解題報(bào)告:

因?yàn)橛幸粭l生成樹內(nèi)的邊必選,所以這是個(gè)切入點(diǎn),我們枚舉生成樹上的每一條邊<U,V>,假設(shè)我們要?jiǎng)h的邊是<U,V>, 那么自然圖就分成了兩塊,這也正是我們要的結(jié)果。我們所要做的就是讓V的子樹上的任何節(jié)點(diǎn),不再和其V子樹外的其他節(jié)點(diǎn)相連。使得他們完全分離開。

有了這個(gè)思路之后,就需要換一個(gè)角色重新考慮問題了,站在新加入的邊的角度上看:對于每一條新加入的一條樹T外的邊<a,b>, ?那么我們需要判斷枚舉到哪一條T內(nèi)的邊的時(shí)候,需要將這條邊刪除掉,不難觀察出來,是ab兩點(diǎn)相連的這條鏈上的邊,那么樹上維護(hù)這條鏈上的邊計(jì)數(shù)+1,就轉(zhuǎn)化成有根樹然后樹上差分即可。

AC代碼:

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e4 + 5; int n,m,val[MAX]; struct Edge {int u,v;int ne; } e[MAX*20]; int tot; int head[MAX],f[MAX]; int fa[MAX][33],dep[MAX]; void add(int u,int v) {e[++tot].u = u;e[tot].v = v;e[tot].ne = head[u];head[u] = tot; } void dfs(int cur,int rt) {fa[cur][0] = rt;dep[cur] = dep[rt] + 1;for(int i = head[cur]; ~i; i = e[i].ne) {int v = e[i].v;if(v == rt) continue;dfs(v,cur);}for(int i = 1; i<=31; i++) {fa[cur][i] = fa[fa[cur][i-1]][i-1];} } int lca(int u,int v) {if(dep[u] < dep[v]) swap(u,v);int dc = dep[u] - dep[v];for(int i = 0; i<=31; i++) {if((1<<i) & dc) u = fa[u][i];}if(u == v) return u;for(int i = 31; i>=0; i--) {if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];}return fa[u][0]; } int ans = 0x3f3f3f3f; void DFS(int cur,int rt) {for(int i = head[cur]; ~i; i = e[i].ne) {if(e[i].v == rt) continue;DFS(e[i].v,cur);val[cur] += val[e[i].v];}if(cur != 1) ans = min(ans,val[cur]); } int main() {int t,iCase=0;cin>>t;while(t--) {scanf("%d%d",&n,&m);tot=0,ans=0x3f3f3f3f;for(int i = 1; i<=n; i++) head[i] = -1,val[i]=0;for(int u,v,i = 1; i<=n-1; i++) {scanf("%d%d",&u,&v);add(u,v);add(v,u);}dfs(1,0);for(int u,v,i = n; i<=m; i++) {scanf("%d%d",&u,&v);val[u]++,val[v]++;val[lca(u,v)]-=2;}DFS(1,0);printf("Case #%d: %d\n",++iCase,ans+1);}return 0 ; }

另一個(gè)解題報(bào)告:https://blog.csdn.net/cqbztsy/article/details/50706555

?

樹形dp做法:https://www.cnblogs.com/qscqesze/p/4822468.html

對于這個(gè)點(diǎn),如果要消除他和他父親之間的聯(lián)系的話,代價(jià)就是他的子樹所有連向外界的邊就好了

跑一遍dfs維護(hù)一下就行了。

(但是好像證明是不對的

2
4?4?1?2?2?3?3?4?1?3
4?4?1?3?2?3?2?4?1?2?

這組數(shù)據(jù),應(yīng)該是1 1,但是下面這個(gè)代碼輸出的是1 2)

//qscqesze #include <cstdio> #include <cmath> #include <cstring> #include <ctime> #include <iostream> #include <algorithm> #include <set> #include <vector> #include <sstream> #include <queue> #include <typeinfo> #include <fstream> #include <map> #include <stack> typedef long long ll; using namespace std; //freopen("D.in","r",stdin); //freopen("D.out","w",stdout); #define sspeed ios_base::sync_with_stdio(0);cin.tie(0) #define maxn 20050 #define mod 10007 #define eps 1e-9 int Num; char CH[20]; //const int inf=0x7fffffff; //нчоч╢С const int inf=0x3f3f3f3f; //*********************************************************************************vector<int> Q[maxn]; vector<int> E[maxn]; int vis[maxn]; int dp[maxn]; int ans; void dfs(int x) {vis[x]=1;for(int i=0;i<Q[x].size();i++){int y=Q[x][i];dfs(Q[x][i]);dp[x]+=dp[y]-1;}ans = min(ans,dp[x]);for(int i=0;i<E[x].size();i++)if(vis[E[x][i]])dp[E[x][i]]--;vis[x]=0; } int main() {int t;scanf("%d",&t);for(int cas = 1;cas<=t;cas++){ans = 99999999;int n,m;scanf("%d%d",&n,&m);for(int i=0;i<=n;i++)Q[i].clear(),E[i].clear();memset(dp,0,sizeof(dp));memset(vis,0,sizeof(vis));for(int i=0;i<n-1;i++){int x,y;scanf("%d%d",&x,&y);dp[x]++,dp[y]++;if(x>y)swap(x,y);Q[x].push_back(y);}for(int i=n-1;i<m;i++){int x,y;scanf("%d%d",&x,&y);dp[x]++,dp[y]++;if(x>y)swap(x,y);E[y].push_back(x);}dfs(1);printf("Case #%d: %d\n",cas,ans);} }

?

總結(jié)

以上是生活随笔為你收集整理的【HDU - 5452】Minimum Cut(树形dp 或 最近公共祖先lca+树上差分,转化tricks,思维)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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