hdu 5452 Minimum Cut(打标记,lca,dfs)
Minimum Cut
Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 1816 Accepted Submission(s): 861
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
题意:
给出一个 \(n\) 个点的无向图,\(m\) 条边,初始时先给出 \(n-1\) 条边,这些边能构成原图的一棵生成树,让后给 \(m-n+1\) 条边,定义原图的一个割是只删除原生成树上的一条边的割,求最小割的边数。
题解:
考虑砍掉每一条树边(转化为考虑删掉每个点和其与父节点连的边),对于非生成树上的树边 \((u,v)\),求他们的 \(lca\) ,假设为 \(f\) ,那么 \(cnt[f]-=2,cnt[u]++,cnt[v]++\),这有点像打标记,然后对树进行一遍 \(dfs\) ,求出每个结点 \(u\) 的子树的 \(cnt\) 和,这就代表了删除 \(u\) 和 \(fa[u]\) 这条边所需要删除的非父边数目,然后扫一遍求最小即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<endl;
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=2e4+100;
int head[maxn];
struct edge
{
int to,next;
}e[maxn*2]; //
int tol=0;
void add(int u,int v)
{
e[++tol].to=v,e[tol].next=head[u],head[u]=tol;
}
int deep[maxn],fa[maxn][17];
void bfs(int rt)
{
queue<int>q;
deep[rt]=0;
fa[rt][0]=rt;
q.push(rt);
while(!q.empty())
{
int t=q.front();
q.pop();
for(int i=1;i<=16;i++)
fa[t][i] = fa[fa[t][i-1]][i-1];
for(int i = head[t];i;i=e[i].next)
{
int v = e[i].to;
if(v==fa[t][0])continue;
deep[v]=deep[t]+1;
fa[v][0]=t;
q.push(v);
}
}
}
int lca(int u,int v)
{
if(deep[u]>deep[v])swap(u,v);
int hu=deep[u],hv=deep[v];
int tu=u,tv=v;
for(int det = hv-hu, i = 0; det ;det>>=1, i++)
if(det&1)
tv = fa[tv][i];
if(tu == tv)return tu;
for(int i =16; i>=0; i--)
{
if(fa[tu][i] == fa[tv][i]) continue;
tu = fa[tu][i];
tv = fa[tv][i];
}
return fa[tu][0];
}
int cnt[maxn];
void dfs(int u,int f)
{
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==f) continue;
dfs(v,u);
cnt[u]+=cnt[v];
}
}
int main()
{
int cas;
scanf("%d",&cas);
int t=0;
while(cas--)
{
int n,m;
scanf("%d%d",&n,&m);
rep(i,1,n+1) head[i]=0,cnt[i]=0;
tol=0;
rep(i,1,n)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
bfs(1);
rep(i,0,m-n+1)
{
int u,v;
scanf("%d%d",&u,&v);
int f=lca(u,v);
cnt[f]-=2;
cnt[u]+=1,cnt[v]+=1;
}
dfs(1,0);
int ans=1e9;
rep(i,2,n+1) ans=min(ans,cnt[i]);
ans++;
printf("Case #%d: %d\n",++t,ans);
}
return 0;
}