codeforces 1082G:G. Petya and Graph(最小割)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37632935/article/details/84654969

题意:给你一个n点m边的图,每个点有个权值,每条边有个权值,让你选择一个边集,然后最大化(边集的权值减去边集中包含的点集的权值)。

思路:BZOJ3894:文理分科类似的题目,建立一个汇点T,每个点i向T连一条容量为a[i]的边,每条边拆成一个点,向这条边所连的两个点连一条容量为INF的边,建立源点S,向每个边拆成的点连一条容量为w的边。答案为sum(w)-最小割。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const ll N = 1e5 + 5;
ll n, m;
ll sp, tp;

struct node{
    ll v, next;
    ll cap;
}edge[N * 2];
ll head[N], deg[N], cur[N];
ll cnt = 0;

void inti()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void add(ll u, ll v, ll cap)
{
    edge[cnt].v = v;
    edge[cnt].cap = cap;
    edge[cnt].next = head[u];
    head[u] = cnt++;

    edge[cnt].v = u;
    edge[cnt].cap = 0;
    edge[cnt].next = head[v];
    head[v] = cnt++;
}

ll bfs()
{
    memset(deg, -1, sizeof(deg));
    deg[sp] = 0;
    queue<ll> q;
    q.push(sp);
    while(!q.empty())
    {
        ll u = q.front();
        if(u == tp) return 1;
        q.pop();
        for(ll i = head[u]; ~i; i = edge[i].next)
        {
            ll v = edge[i].v;
            ll cap = edge[i].cap;
            if(deg[v] == -1 && cap)
            {
                deg[v] = deg[u] + 1;
                q.push(v);

            }
        }
    }
    return 0;
}

ll dfs(ll u, ll flow)
{
    if(u == tp || flow == 0) return flow;
    ll res = 0, f;
    for(ll &i = cur[u]; ~i; i = edge[i].next)
    {
        ll v = edge[i].v;
        ll cap = edge[i].cap;
        if(deg[v] == deg[u] + 1 && (f = dfs(v, min(flow - res,cap))) > 0)
        {
            edge[i].cap -= f;
            edge[i ^ 1].cap += f;
            res += f;
            if(res == flow) return flow;
        }
    }
    if(!res) deg[u] = -1;
    return res;
}

ll dinic()
{
    ll ans = 0;
    while(bfs())
    {
        memcpy(cur, head, sizeof(head));
        ans += dfs(sp, INF);
    }
    return ans;
}

int main()
{
    cin >> n >> m;
    sp = 0, tp = n+m+1;
    inti();ll sum=0;
    for(ll i=1;i<=n;i++)
    {
    	ll x;cin>>x;
    	add(i,tp,x);
	}
    for(ll i = 1,j=i+n; i <= m; i++,j++)
    {
    	ll u,v,x;
    	scanf("%lld %lld %lld",&u,&v,&x);
    	add(sp,j,x);sum+=x;
    	add(j,u,10000000000000000);
    	add(j,v,10000000000000000);
    }
    cout << sum-dinic() << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37632935/article/details/84654969