poj 2987 最大权闭合图 最大流最小割模板

来源:互联网 发布:顾家家居怎么样知乎 编辑:程序博客网 时间:2024/06/08 02:23

题意:

有一公司,公司里每个人都有自己的贡献值和自己的下属,下属也有下属。

现在要裁员,每裁掉一个人,他的下属也要被裁掉,下属的下属依次类推也要裁掉。

现在问,最小的裁员量和裁员完了以后最大的贡献值。


解析:

http://www.hankcs.com/program/algorithm/poj-2987-firing.html

最大权闭合图。

主要学习这种建图的抽象思维。

                

   ------------------------------->

发现原来的dinic模板算残量的时候有问题,EK的话MLE,加边还是MLE。


代码:

#pragma comment(linker, "/STACK:1677721600")#include <map>#include <set>#include <cmath>#include <queue>#include <stack>#include <vector>#include <cstdio>#include <cstdlib>#include <cstring>#include <climits>#include <cassert>#include <iostream>#include <algorithm>#define pb push_back#define mp make_pair#define LL long long#define lson lo,mi,rt<<1#define rson mi+1,hi,rt<<1|1#define Min(a,b) ((a)<(b)?(a):(b))#define Max(a,b) ((a)>(b)?(a):(b))#define mem0(a) memset(a,0,sizeof(a))#define mem1(a) memset(a,-1,sizeof(a))#define mem(a,b) memset(a,b,sizeof(a))#define FIN freopen("in.txt", "r", stdin)#define FOUT freopen("out.txt", "w", stdout)using namespace std;const int mod = 1e9 + 7;const double eps = 1e-8;const double ee = exp(1.0);const int inf = 0x3f3f3f3f;const int maxn = 100000 + 10;const double pi = acos(-1.0);const LL iinf = 0x3f3f3f3f3f3f3f3f;int readT(){    char c;    int ret = 0,flg = 0;    while(c = getchar(), (c < '0' || c > '9') && c != '-');    if(c == '-') flg = 1;    else ret = c ^ 48;    while( c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c ^ 48);    return flg ? - ret : ret;}struct Edge{    int to, rev;    LL cap;    Edge(int to, LL cap, int rev):to(to),cap(cap),rev(rev){}};vector<Edge> g[maxn];       //图的邻接表int lev[maxn];              //顶点到源点的距离标号int iter[maxn];             //当前弧,在其之前的边已经没用了//向图中加入一条从fr到to的容量为cap的边void addEdge(int fr, int to, LL cap){    g[fr].pb(Edge(to, cap, g[to].size()));    g[to].pb(Edge(fr, 0, g[fr].size() - 1));}//bfs计算从源点出发的距离标号void bfs(int s){    mem1(lev);    queue<int> q;    lev[s] = 0;    q.push(s);    while (!q.empty())    {        int v = q.front();        q.pop();        for (int i = 0; i < g[v].size(); i++)        {            Edge& e = g[v][i];            if (0 < e.cap && lev[e.to] == -1)            {                lev[e.to] = lev[v] + 1;                q.push(e.to);            }        }    }}//dfs找增广路径LL dfs(int v, int t, LL f){    if (v == t)        return f;    int sz = g[v].size();    for (int& i = iter[v]; i < sz; i++)    {        Edge& e = g[v][i];        if (0 < e.cap && lev[v] < lev[e.to])        {            LL d = dfs(e.to, t, Min(f, e.cap));            if (d)            {                e.cap -= d;                g[e.to][e.rev].cap += d;                return d;            }        }    }    return 0;}LL maxFlow(int s, int t){    LL flow = 0;    while (1)    {        bfs(s);        if (lev[t] < 0)            return flow;        mem0(iter);        LL f;        while ((f = dfs(s, t, inf)) > 0)            flow += f;    }}int vertexNum, vis[maxn];//遍历残余网络找点void minCut(int v){    int sz = g[v].size();    for (int i = 0; i < sz; i++)    {        Edge& e = g[v][i];        if (!vis[e.to] && 0 < e.cap)        {            vis[e.to] = true;            vertexNum++;            minCut(e.to);        }    }}int main(){#ifdef LOCAL    FIN;#endif // LOCAL    int n, m;    while (~scanf("%d%d", &n, &m))    {        for (int i = 0; i <= n + 1; i++)            g[i].clear();        LL sum = 0;        int s = 0, t = n + 1;        for (int i = 1; i <= n; i++)        {            int x = readT();            if (x < 0)            {                addEdge(i, t, -x);            }            else            {                sum += x;                addEdge(s, i, x);            }        }        for (int i = 1; i <= m; i++)        {            int fr = readT();            int to = readT();            addEdge(fr, to, inf);        }        sum -= maxFlow(s, t);        vertexNum = 0;        mem0(vis);        vis[s] = true;        minCut(s);        //-汇点        printf("%d %lld\n", vertexNum, sum);    }    return 0;}




0 0
原创粉丝点击