【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,n個點m條邊,圖中給定一顆生成樹(前n-1條輸入的邊)。問一個最小割的邊數量(將圖變成一個不連通圖),要求需要包含給定生成樹內的一條邊。
解題報告:
因為有一條生成樹內的邊必選,所以這是個切入點,我們枚舉生成樹上的每一條邊<U,V>,假設我們要刪的邊是<U,V>, 那么自然圖就分成了兩塊,這也正是我們要的結果。我們所要做的就是讓V的子樹上的任何節點,不再和其V子樹外的其他節點相連。使得他們完全分離開。
有了這個思路之后,就需要換一個角色重新考慮問題了,站在新加入的邊的角度上看:對于每一條新加入的一條樹T外的邊<a,b>, ?那么我們需要判斷枚舉到哪一條T內的邊的時候,需要將這條邊刪除掉,不難觀察出來,是ab兩點相連的這條鏈上的邊,那么樹上維護這條鏈上的邊計數+1,就轉化成有根樹然后樹上差分即可。
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 ; }另一個解題報告:https://blog.csdn.net/cqbztsy/article/details/50706555
?
樹形dp做法:https://www.cnblogs.com/qscqesze/p/4822468.html
對于這個點,如果要消除他和他父親之間的聯系的話,代價就是他的子樹所有連向外界的邊就好了
跑一遍dfs維護一下就行了。
(但是好像證明是不對的
2
4?4?1?2?2?3?3?4?1?3
4?4?1?3?2?3?2?4?1?2?
這組數據,應該是1 1,但是下面這個代碼輸出的是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);} }?
總結
以上是生活随笔為你收集整理的【HDU - 5452】Minimum Cut(树形dp 或 最近公共祖先lca+树上差分,转化tricks,思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用债违约,债券基金还能买吗?
- 下一篇: 全红婵再现水花消失术:结果却只能屈居第二