Minimum Cut
Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 2384 Accepted Submission(s): 1120
Problem Description
Given a simple unweighted graph G (an undirected graph containing no loops nor multiple edges) with n nodes and m edges. Let T be a spanning tree of G.
We say that a cut in G respects T if it cuts just one edges of T.
Since love needs good faith and hypocrisy return for only grief, you should find the minimum cut of graph G respecting the given spanning tree T.
Input
The input contains several test cases.
The first line of the input is a single integer t (1≤t≤5) which is the number of test cases.
Then t test cases follow.
Each test case contains several lines.
The first line contains two integers n (2≤n≤20000) and m (n−1≤m≤200000).
The following n−1 lines describe the spanning tree T and each of them contains two integers u and v corresponding to an edge.
Next m−n+1 lines describe the undirected graph G and each of them contains two integers u and v corresponding to an edge which is not in the spanning tree T.
Output
For each test case, you should output the minimum cut of graph G respecting the given spanning tree T.
Sample Input
1 4 5 1 2 2 3 3 4 1 3 1 4
Sample Output
Case #1: 2
Source
2015 ACM/ICPC Asia Regional Shenyang Online
遍历每一条树边,每一条树边把树分为两部分,要想使图不连通,除了减掉这条树边,还需要减去连接这两个部分的非树边,我们对所有非树边连接的两个点u,v,num[u]++,num[v]++,然后dfs出其中一部分树所有点num的和,但这样做会把连接树内部的非树边也减去,还需要num[lca(u,v)]+=2
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 20010;
const int INF = 0x3f3f3f3f;
int num[MAXN];
//-----------------ST + 倍增 在线LCA模板------------------//
int rmq[2 * MAXN];
struct ST
{
int mm[2 * MAXN];
int dp[2 * MAXN][20];
void init(int n)
{
mm[0] = -1;
for(int i = 1; i <= n; i++) {
mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
dp[i][0] = i;
}
for(int j = 1; j <= mm[n]; j++) {
for(int i = 1; i + (1 << j) - 1 <= n; i++) {
dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j
- 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1];
}
}
}
int query(int a,int b)
{
if(a > b) swap(a,b);
int k = mm[b - a + 1];
return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] :
dp[b - (1 << k) + 1][k];
}
};
struct Edge
{
int to,Next;
};
Edge edge[MAXN * 2];
int tot,head[MAXN];
int F[MAXN * 2];
int P[MAXN];
int cnt;
ST st;
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
}
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].Next = head[u];
head[u] = tot++;
}
void dfs(int u,int pre,int dep)
{
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = head[u]; i != -1; i = edge[i].Next) {
int v = edge[i].to;
if(v == pre) continue;
dfs(v,u,dep + 1);
F[++cnt] = u;
rmq[cnt] = dep;
}
}
void LCA_init(int root,int node_num)
{
cnt = 0;
dfs(root,root,0);
st.init(2 * node_num - 1);
}
int query_lca(int u,int v)
{
return F[st.query(P[u],P[v])];
}
//-----------------ST + 倍增 在线LCA模板------------------//
void DFS(int u,int fa)
{
for(int i = head[u]; i != -1; i = edge[i].Next) {
int v = edge[i].to;
if(v == fa) continue;
DFS(v,u);
num[u] += num[v];
}
}
int main(void)
{
int T;
int n,m,u,v;
int kase = 0,root;
int ans;
scanf("%d",&T);
while(T--) {
init();
kase++;
scanf("%d %d",&n,&m);
for(int i = 1; i < n; i++) {
scanf("%d %d",&u,&v);
addedge(u,v);
addedge(v,u);
}
LCA_init(1,n);
for(int i = 1; i <= m - (n - 1); i++) {
scanf("%d %d",&u,&v);
num[u]++;num[v]++;
num[query_lca(u,v)] -= 2;
}
DFS(1,1);
ans = INF;
for(int i = 2; i <= n; i++) {
ans = min(ans,num[i] + 1);
}
printf("Case #%d: %d\n",kase,ans);
}
return 0;
}
/*
1
4 5
1 2
2 3
3 4
1 3
1 4
*/