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;
}
posted @ 2017-09-21 14:14  tarjan's  阅读(148)  评论(0编辑  收藏  举报