HDU 3879 Base Station 最大权闭合图

题目链接:点击打开链接

题意:

给定n个带权点m条无向带权边

选一个子图,则这个子图的权值为 边权和-点权和

求一个最大的权值

把边也当成点。然后是最大权闭合图

dinic:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
//点标 从0开始 F.Init(n) n=最大点标+10
const int N = 200010;
const int M = 500010;
const int INF = ~0u >> 2;
template<class T>
struct Max_Flow {
    int n;
    int Q[N], sign;
    int head[N], level[N], cur[N], pre[N];
    int nxt[M], pnt[M], E;
    T cap[M];
    void Init(int n) {
        this->n = n;
        E = 0;
        std::fill(head, head + n, -1);
    }
    //有向rw 就= 0
    void add(int from, int to, T c, T rw) {
        pnt[E] = to;
        cap[E] = c;
        nxt[E] = head[from];
        head[from] = E++;

        pnt[E] = from;
        cap[E] = rw;
        nxt[E] = head[to];
        head[to] = E++;
    }
    bool Bfs(int s, int t) {
        sign = t;
        std::fill(level, level + n, -1);
        int *front = Q, *tail = Q;
        *tail++ = t; level[t] = 0;
        while(front < tail && level[s] == -1) {
            int u = *front++;
            for(int e = head[u]; e != -1; e = nxt[e]) {
                if(cap[e ^ 1] > 0 && level[pnt[e]] < 0) {
                    level[pnt[e]] = level[u] + 1;
                    *tail ++ = pnt[e];
                }
            }
        }
        return level[s] != -1;
    }
    void Push(int t, T &flow) {
        T mi = INF;
        int p = pre[t];
        for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {
            mi = std::min(mi, cap[p]);
        }
        for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {
            cap[p] -= mi;
            if(!cap[p]) {
                sign = pnt[p ^ 1];
            }
            cap[p ^ 1] += mi;
        }
        flow += mi;
    }
    void Dfs(int u, int t, T &flow) {
        if(u == t) {
            Push(t, flow);
            return ;
        }
        for(int &e = cur[u]; e != -1; e = nxt[e]) {
            if(cap[e] > 0 && level[u] - 1 == level[pnt[e]]) {
                pre[pnt[e]] = e;
                Dfs(pnt[e], t, flow);
                if(level[sign] > level[u]) {
                    return ;
                }
                sign = t;
            }
        }
    }
    T Dinic(int s, int t) {
        pre[s] = -1;
        T flow = 0;
        while(Bfs(s, t)) {
            std::copy(head, head + n, cur);
            Dfs(s, t, flow);
        }
        return flow;
    }
};
Max_Flow <int>F;
int n, m;
int work(){
    F.Init(n+m+10);
    int from = 0, to = n + m +1, A;
    for(int i = 1; i <= n; i++){
        scanf("%d", &A);
        F.add(i, to, A, 0);
    }
    int u, v, d, all = 0;
    for(int i = 1; i <= m; i++){
        scanf("%d %d %d", &u, &v, &d);
        all += d;
        F.add(from, n+i, d, 0);
        F.add(n+i, u, INF, 0);
        F.add(n+i, v, INF, 0);
    }
    return all - F.Dinic(from, to);
}
int main(){
    while(cin>>n>>m)
        cout<<work()<<endl;
    return 0;
}
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define ll int
const int MAXN = 100010;//点数的最大值
const int MAXM = 400010;//边数的最大值
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow;
}edge[MAXM];//注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
void add(int u,int v,int w,int rw = 0)
{
    edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
    edge[tol].next = head[u]; head[u] = tol++;
    edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
    edge[tol].next = head[v]; head[v] = tol++;
}
int Q[MAXN];
void BFS(int start,int end)
{
    memset(dep,-1,sizeof(dep));
    memset(gap,0,sizeof(gap));
    gap[0] = 1;
    int front = 0, rear = 0;
    dep[end] = 0;
    Q[rear++] = end;
    while(front != rear)
    {
        int u = Q[front++];
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(dep[v] != -1)continue;
            Q[rear++] = v;
            dep[v] = dep[u] + 1;
            gap[dep[v]]++;
        }
    }
}
int S[MAXN];
int sap(int start,int end,int N)
{
    BFS(start,end);
    memcpy(cur,head,sizeof(head));
    int top = 0;
    int u = start;
    int ans = 0;
    while(dep[start] < N)
    {
        if(u == end)
        {
            int Min = INF;
            int inser;
            for(int i = 0;i < top;i++)
                if(Min > edge[S[i]].cap - edge[S[i]].flow)
                {
                    Min = edge[S[i]].cap - edge[S[i]].flow;
                    inser = i;
                }
            for(int i = 0;i < top;i++)
            {
                edge[S[i]].flow += Min;
                edge[S[i]^1].flow -= Min;
            }
            ans += Min;
            top = inser;
            u = edge[S[top]^1].to;
            continue;
        }
        bool flag = false;
        int v;
        for(int i = cur[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].to;
            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])
            {
                flag = true;
                cur[u] = i;
                break;
            }
        }
        if(flag)
        {
            S[top++] = cur[u];
            u = v;
            continue;
        }
        int Min = N;
        for(int i = head[u]; i != -1; i = edge[i].next)
            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
            {
                Min = dep[edge[i].to];
                cur[u] = i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])return ans;
        dep[u] = Min + 1;
        gap[dep[u]]++;
        if(u != start)u = edge[S[--top]^1].to;
    }
    return ans;
}
void init(){ tol = 0; memset(head,-1,sizeof(head)); }

int n, m;
ll work(){
    init();
    int from = 0, to = n + m +1, A;
    for(int i = 1; i <= n; i++){
        scanf("%d", &A);
        add(i, to, A);
    }
    int u, v; ll d;
    ll all = 0;
    for(int i = 1; i <= m; i++){
        scanf("%d %d %d", &u, &v, &d);
        all += d;
        add(from, n+i, d);
        add(n+i, u, INF);
        add(n+i, v, INF);
    }
    return all - sap(from, to,to+1);
}
int main(){
    while(cin>>n>>m)
        cout<<work()<<endl;
    return 0;
}
时间: 2024-11-08 19:24:24

HDU 3879 Base Station 最大权闭合图的相关文章

HDU 3879 Base Station(最小割---最大权闭合)

题目地址:HDU 3879 无语...对这题的数据范围无语..刚上来一看,建图思路很快出来了,但是一看数据范围..需要5w个点..于是我以为需要缩点或是别的优化..于是又想了会怎么优化,感觉没法优化了..于是上网一搜..还真都是就这么过了...过了..过了..于是,我就按刚上来那个思路敲,结果203ms过了...我真怀疑出题者是不是不小心把数据范围多写了几个0.这要放在比赛中..肯定不敢这么写... 建图思路是,对所有任务额外建一个点,并连源点,权值为任务的获利.然后将每个任务所对应的站点连边,

HDU 3879 Base Station(最大权闭合子图)

经典例题,好像说可以转化成maxflow(n,n+m),暂时只可以勉强理解maxflow(n+m,n+m)的做法. 题意:输入n个点,m条边的无向图.点权为负,边权为正,输出最大权闭合子图的权值. (最大权闭合子图:图中各点的后继必然也在图中) 构图攻略:将边看做点(有的题边是没有权的,建模稍微有点不同), 对原本的边e[i](u,v,w)连3条边(S,n+i,w),(n+i,u,inf),(n+i,v,inf). 对原本的点v,连1条边(v,T,p[v]). 即正权点与源点连,负权点与汇点连.

hdu 3917 Road constructions 最大权闭合图

Road constructions Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1470    Accepted Submission(s): 485 Problem Description N cities are required to connect with each other by a new transportatio

hdu 5772 String problem(最大权闭合图)

题目链接:hdu 5772 String problem 题意: 给你一个字符串,只含有数字. 你需要选择出一个子序列,使得这个子序列的权值最大. 这个子序列如果这个数字第一次出现就ans-=bx,否则就-=ax 然后如果第i个字符和第j个字符都在子序列里面,那么ans+=w[i][j] 问你最大ans是多少 官方题解: 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace

HDU 3879:Base Station(最大权闭合图)

http://acm.hdu.edu.cn/showproblem.php?pid=3879 http://www.lydsy.com/JudgeOnline/problem.php?id=1497 题意:给出n个点m条边,其中每个点有一个权值代表修建这个点需要耗费的钱,然后m条边里面,代表如果两个修建好的点相连的话,那么可以得到一点利润.求最大的获利. 思路:和BZOJ 1497是同一道题目.学习最大权闭合图的题目,看了一下不清楚应该怎么建图,然后只好搜一个论文来看看.http://wenku

Base Station (hdu 3879 最大权闭合图)

Base Station Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65768/32768 K (Java/Others) Total Submission(s): 1983    Accepted Submission(s): 838 Problem Description A famous mobile communication company is planning to build a new set of base

hdu 3879 hdu 3917 构造最大权闭合图 俩经典题

hdu3879  base station : 各一个无向图,点的权是负的,边的权是正的.自己建一个子图,使得获利最大. 一看,就感觉按最大密度子图的构想:选了边那么连接的俩端点必需选,于是就以边做点,轻轻松松构造了最大权闭合图.简单题.分分钟搞定. hdu3917 :road  constructions :这题题目看了半天没理解...感觉描述的不好...一个有向图,每条路有响应公司承保,若选了该公司,那么该公司的路必需全部选,还有,该公司的承保的路的下面的一条路对应公司也要选,求最大获利.构

hdu 3879 最大权闭合图(裸题)

/* 裸的最大权闭合图 解:参见胡波涛的<最小割模型在信息学竞赛中的应用> */ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> using namespace std; #define N 55100//刚开始开的是5100一直越界应该是n+m #define NN 510000 #define inf 0x3fffffff struct node

HDU 3061:Battle(最大权闭合图)

http://acm.hdu.edu.cn/showproblem.php?pid=3061 题意:中文题意. 思路:和上一题神似啊,比上一题还简单,重新看了遍论文让我对这个理解更加深了. 闭合图:如果某个点在图中的话,那么这个点的后继点全部都要在图中. 对应至题目,这里的必须攻占b以后才能攻占a,那么是a依赖于b.如果a在图中的话,那么b必定在图中(因为a是依赖于b的),所以是a连向b(而不是b连向a). 这里总结一下做最大权闭合图的套路:把权值为正的点与超级源点S相连,容量为该权值,把权值为