Minimum Cut

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

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 80010;
const int M = 26;


struct Edge
{
    int from, to;
    int nt;
} edge[2*N];
int head[N],cnt;
void add_edge(int u, int v){
    edge[cnt].from = u;
    edge[cnt].to = v;
    edge[cnt].nt = head[u];
    head[u] = cnt++;
}


//tot:时间戳,ver:节点编号 dep:深度 in:点编号位置
int tot,ver[2*N], dep[2*N], in[N],out[N];
void dfs(int x ,int pre){
    ver[++tot] = x;
    in[x] = tot;
    for(int i=head[x]; i!=-1; i=edge[i].nt){
        Edge& e=edge[i];
        if(e.to==pre)continue;
        dep[e.to]=dep[x]+1;
        dfs(e.to,x);
        ver[++tot] = x;//从子树回来
    }
    out[x]=tot;
}

int dp[2*N][M];  //数组开到2*N,因为遍历后序列长度为2*n-1
void ST(int n)
{
    for(int i=1; i<=n; i++)dp[i][0] = ver[i];//维护真实id
    for(int j=1; (1<<j)<=n; j++){
        for(int i=1; i+(1<<j)-1<=n; i++){
            int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
            dp[i][j] = dep[a]<dep[b]?a:b;
        }
    }
}

//中间部分是交叉的。
int RMQ(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1) k++;
    int a = dp[l][k], b = dp[r-(1<<k)+1][k];
    return dep[a]<dep[b]?a:b;
}

int LCA(int u ,int v)
{
    int x = in[u] , y = in[v];
    if(x > y) swap(x,y);
    int res = RMQ(x,y);
    return res;
}

int num[N];
int DFS(int u,int fa)
{
    for(int i = head[u]; ~i; i = edge[i].nt) {
        int v = edge[i].to;
        if(v == fa)continue;
        DFS(v, u);
        num[u]+=num[v];
    }
    return 0;
}


void init()
{
    memset(head,-1,sizeof(head));
    memset(num,0,sizeof(num));
    cnt =tot=0;
}
/*
1
7 10

1 2
2 3
3 4
1 5
5 6
6 7

1 4
2 4
1 7
5 7
*/
int main()
{
    int t;
    int cas=0;
    int n, m;
    scanf("%d",&t);
    while(t--){
        init();
        scanf("%d%d",&n,&m);
        int u, v;
        for(int i = 0; i < n-1; i++){
            scanf("%d%d",&u,&v);
            add_edge(u, v);
            add_edge(v, u);
        }

        dfs(1,0);
        ST(tot);
       // printf("tot:%d\n",tot);

       // for(int i=1;i<=tot;i++)    printf("i:%d  %d\n",i,ver[i]);

        for(int i = n; i <= m; i++)
        {
            scanf("%d%d",&u,&v);
            int tt = LCA(u, v);
            //printf("u:%d v:%d inu:%d inv:%d tt:%d\n",u,v,in[u],in[v],tt);
            num[u]++;
            num[v]++;
            num[tt]-=2;//一条边两个端点 贡献为2
        }

        DFS(1, 1);
        int ans = INF;
        for(int i = 2; i <= n; i++)
        {
            ans = min(ans, num[i]+1);
           // printf("i:%d num:%d\n",i,num[i]);
        }
        printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值