hdoj 5452 Minimum Cut 【LCA or 树链剖分】

本文深入探讨了深度学习在人工智能领域的应用,包括神经网络、机器学习算法及其在图像处理、自然语言处理和强化学习等领域的实践案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



Minimum Cut

Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 658    Accepted Submission(s): 292


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 (1t5) 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 (2n20000) and m (n1m200000).
The following n1 lines describe the spanning tree T and each of them contains two integers u and v corresponding to an edge.
Next mn+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
 




意:给出一个图G和它的一个生成树T。现在要求删除生成树上的一条边和若干条其他边,使得图不连通。求能删除的最小边数。


思路:LCA 修改、记录每个点被覆盖环的次数,最后找出最小的覆盖次数+1就可以了。


AC代码:


#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 20000+10
#define MAXM 200000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int to, next;
};
Edge edge[MAXM<<1];
int head[MAXN], edgenum;
int depth[MAXN];
int pre[MAXN];//记录节点前驱
int num[MAXN];//记录节点被环覆盖的次数
int N, M;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v)
{
    edge[edgenum].to = v;
    edge[edgenum].next = head[u];
    head[u] = edgenum++;
}
void getMap()
{
    init();
    scanf("%d%d", &N, &M);
    int a, b;
    for(int i = 1; i < N; i++)
    {
        num[i] = 0;
        scanf("%d%d", &a, &b);
        addEdge(a, b);
        addEdge(b, a);
    }
}
void DFS(int u, int fa, int d)
{
    depth[u] = d;//记录深度
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == fa) continue;
        pre[v] = u;
        DFS(v, u, d+1);
    }
}
void find_depth()
{
    memset(depth, 0, sizeof(depth));
    memset(pre, 0, sizeof(pre));
    DFS(1, -1, 0);
}
int k = 1;
void work(int e1, int e2)
{
    while(1)//到达LCA
    {
        if(depth[e1] > depth[e2])
        {
            num[e1]++;
            e1 = pre[e1];
        }
        else
        {
            num[e2]++;
            e2 = pre[e2];
        }
        if(e1 == e2)
        {
            num[e1]++;
            break;
        }
    }
}
void solve()
{
    find_depth();
    int a, b;
    for(int i = 0; i < M-N+1; i++)
    {
        scanf("%d%d", &a, &b);
        if(a == b)
        {
            num[a]++;
            continue;
        }
        work(a, b);//对树边处理
    }
    int ans = INF;
    for(int i = 1; i <= N; i++)//求最小次数 环覆盖
        ans = min(num[i]+1, ans);
    printf("Case #%d: %d\n", k++, ans);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        getMap();
        solve();
    }
    return 0;
}

树链剖分:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (20000+10)
#define MAXM (300000+10)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while((a)--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
#pragma comment(linker, "/STACK:102400000,102400000")
#define fi first
#define se second
using namespace std;
struct Edge{
    int from, to, next;
};
Edge edge[MAXN<<1];
int head[MAXN], edgenum;
void init(){
    edgenum = 0; CLR(head, -1);
}
void addEdge(int u, int v)
{
    Edge E = {u, v, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
int son[MAXN], num[MAXN];
int top[MAXN], pos[MAXN], id;
int dep[MAXN], pre[MAXN];
void DFS1(int u, int fa, int d)
{
    dep[u] = d; pre[u] = fa; num[u] = 1; son[u] = -1;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == fa) continue;
        DFS1(v, u, d+1);
        num[u] += num[v];
        if(son[u] == -1 || num[son[u]] < num[v])
            son[u] = v;
    }
}
void DFS2(int u, int T)
{
    top[u] = T; pos[u] = ++id;
    if(son[u] == -1) return ;
    DFS2(son[u], T);
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre[u] || v == son[u]) continue;
        DFS2(v, v);
    }
}
int ans[MAXN];
void Update(int u, int v)
{
    int f1 = top[u], f2 = top[v];
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(u, v);
            swap(f1, f2);
        }
        ans[pos[f1]]++; ans[pos[u]+1]--;
        u = pre[f1], f1 = top[u];
    }
    if(u == v) return ;
    if(dep[u] > dep[v]) swap(u, v);
    ans[pos[son[u]]]++; ans[pos[v]+1]--;
}
int main()
{
    int t, kcase = 1; Ri(t);
    W(t)
    {
        int n, m; Ri(n); Ri(m); init();
        int s, e;
        for(int i = 1; i <= n-1; i++)
        {
            Ri(s); Ri(e);
            addEdge(s, e);
            addEdge(e, s);
        }
        DFS1(1, -1, 1); id = 0; DFS2(1, 1);
        CLR(ans, 0);
        for(int i = n; i <= m; i++)
        {
            Ri(s); Ri(e);
            Update(s, e);
        }
        int Min = INF;
        for(int i = 2; i <= id; i++)
        {
            ans[i] += ans[i-1];
            Min = min(ans[i], Min);
        }
        printf("Case #%d: %d\n", kcase++, Min+1);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值