2021年度训练联盟热身训练赛第四场 E题.How Many to Be Happy?(最小割)

题目链接
题意:

给出一个无向图,问对于每条边,最少需要删掉多少条边才能使得这条边在图的最小生成树中。

题解:

先对边权排序,假设我们要使 e i e_i ei 这条边在最小生成树中,那么边权小于 e i e_i ei 的边构成的图不能使得 e i e_i ei的两个端点是连通的,否则这条边就无法加入到最小生成树中,那么也就是说,我们要求构造出来的图最少删掉多少条边,才能使得 e i e_i ei 两个端点不连通, 那么就转化为最小割的问题,源点和汇点是 e i e_i ei 的两个端点。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=5e2+5;
const int inf=0x3f3f3f3f;
#define INF 1e18
const int M =5e2+5;
int cnt =0, head[MAXN], dis[MAXN], cur[MAXN];
struct edge
{
    int to, next;
    ll cost;          
} e[M<< 1]; ///共有n*2条边
void add(int from, int to, ll value)
{ ///链式前向星
    e[cnt].to = to;
    e[cnt].cost = value;
    e[cnt].next = head[from];
    head[from] = cnt++;
}
int bfs(int st, int ed)
{ ///建立层次图
    queue<int> que;
    memset(dis, -1, sizeof(dis));
    dis[st] = 0;
    que.push(st);
    while (!que.empty())
    {
        int x = que.front();
        que.pop();
        for (int i = head[x]; i > -1; i = e[i].next)
        {
            int now = e[i].to;
            if (dis[now] == -1 && e[i].cost)
            {
                que.push(now);
                dis[now] = dis[x] + 1;
            }
        }
    }
    return dis[ed] != -1;
}
ll dfs(int x, int t,ll maxflow)
{
    if (x == t)
        return maxflow;
    ll ans = 0;
    for (int i = cur[x]; i > -1; i = e[i].next)
    { ///当前弧优化
        int now = e[i].to;
        if (dis[now] != dis[x] + 1 || e[i].cost == 0 || ans >= maxflow)
            continue;
        cur[x] = i;
        ll f = dfs(now, t, min(e[i].cost, maxflow - ans));
        e[i].cost -= f;
        e[i ^ 1].cost += f; ///反向边加流量
        ans += f;
    }
    if (!ans)
        dis[x] = -1; ///炸点优化
    return ans;
}
int Dinic(int st, int ed)//起点,终点
{
    ll ans = 0;
    while (bfs(st, ed))
    {
        memcpy(cur, head, sizeof(head));
        ll k;
        while ((k = dfs(st, ed, INF)))
            ans += k;
    }
    return ans;
}
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
}
struct ENGE
{
    int a,b,w;
    /* data */
}f[MAXN];
bool cmp(ENGE x,ENGE y)
{
    return x.w<y.w;
}
int main()
{
//========================================
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
//=========================================
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>f[i].a>>f[i].b>>f[i].w;
    }
    sort(f+1,f+1+m,cmp);
    int ans=0;
    for(int i=2;i<=m;i++)
    {
        init();
        for(int j=1;j<i;j++)
        {
            if(f[j].w==f[i].w) break;
            add(f[j].a,f[j].b,1);
            add(f[j].b,f[j].a,1);
            
        }
        ans+=Dinic(f[i].a,f[i].b);
    }
    cout<<ans<<endl;
}

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页