【HDU - 5452】Minimum Cut(树形dp 或 最近公共祖先lca+树上差分,转化tricks,思维)
題干:
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 4Sample 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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用债违约,债券基金还能买吗?
- 下一篇: 【HDU - 1024 】Max Sum