Minimum Cut
Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 2371 Accepted Submission(s): 1112
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
题意就贼JB坑(英语太差),数据更坑,数据貌似特别水。。。
题意: 首先给你一个生成树,然后给你几条非树边,现在你要当且仅当删除树边一条,删除非树边若干条,使得剩下的图为一个不连通的。
思路: 删除树边是一定的,,那么这样我可以枚举删除每一条树边,然后看如果删除这条树边的话,那么我还要删除多少条非树边,那么我要删除的非树边其实就是这条非树边的两个顶点分别在树边的左右两边。 这样我就可以先预处理出来所有的非树边对树边的影响,这里一个技巧一点的实现方法就是对于非树边的两个点u,v 对于uv 的LCA 我 -=2 ,然后对于u v +=1 这样在dfs回溯的时候直接更新一下val就可以,我们要找的就是除了根结点的最小的val (这里就是把每条边对应他的v点)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =2e4+5;
const int M =400005;
struct eee
{
int v;
int next;
}edge[M];
struct node
{
int u,v;
}E[M];
int rmq[N*2]; /// 就是欧拉序列对应的深度序列
struct ST
{
int mm[N*2];
int anc[2*N][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];
anc[i][0]=i;
}
for(int j=1;j<=mm[n];j++){
for(int i=1;i+(1<<j)-1<=n;i++){
anc[i][j]=rmq[anc[i][j-1]] < rmq[anc[i+(1<<(j-1))][j-1]]?anc[i][j-1]:anc[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[anc[a][k]] <= rmq[anc[b-(1<<k)+1][k]]?anc[a][k]:anc[b-(1<<k)+1][k];
}
};
int tot,head[N];
int val[N];
int dfns[N*2];
int pp[N];
int cnt;
int clo;
ST st;
int n,m;
void init()
{
tot=0;
clo=cnt=0;
memset(head,-1,sizeof(head));
memset(val,0,sizeof(val));
}
void add(int u,int v)
{
edge[++tot].v=v; edge[tot].next=head[u]; head[u]=tot;
}
void dfs(int u,int fa,int deep)
{
dfns[++cnt]=u; rmq[cnt]=deep; pp[u]=cnt;
//L[u]=++clo;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==fa) continue;
dfs(v,u,deep+1);
dfns[++cnt]=u;
rmq[cnt]=deep;
}
//R[u]=clo;
}
void LCA_init(int rt,int node_num)
{
cnt=0;
dfs(rt,rt,0);
st.init(2*node_num-1);
}
int LCA(int u,int v)
{
return dfns[st.query(pp[u],pp[v])];
}
void dfs1(int u,int fa)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==fa) continue;
dfs1(v,u);
val[u]+=val[v];
}
}
int main()
{
int T;
scanf("%d",&T);
int kk=0;
while(T--)
{
scanf("%d %d",&n,&m);
int i;
init();
for(i=1;i<n;i++){
scanf("%d %d",&E[i].u,&E[i].v);
add(E[i].u,E[i].v);
add(E[i].v,E[i].u);
}
LCA_init(1,n);
for(;i<=m;i++){
scanf("%d %d",&E[i].u,&E[i].v);
int lca=LCA(E[i].u,E[i].v);
//cout<<"lca "<<lca<<endl;
val[lca]-=2;
val[E[i].u]++;
val[E[i].v]++;
}
dfs1(1,-1);
int Ans=99999999;
for(int i=2;i<=n;i++){
Ans=min(Ans,val[i]);
}
printf("Case #%d: %d\n",++kk,Ans+1);
}
return 0;
}