poj 3469 Dual Core CPU (最小割->最大流)

来源:互联网 发布:打车软件 技术方案 编辑:程序博客网 时间:2024/05/17 03:28

这题不难,很容易建立最小割模型,然后就是最大流啦。顺便贴上我的SAP模板,此模板是我参考了网上众牛的模板写的,集各种优化于一身。

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;const int maxn = 20010;const int maxm = 999999;const int oo = 1 << 30;int n, m, idx;int cur[maxn], pre[maxn];int dis[maxn], gap[maxn];int aug[maxn], head[maxn];struct Node{int u, v, w;int next;}edge[maxm];void addEdge(int u, int v, int w){    edge[idx].u = u;    edge[idx].v = v;    edge[idx].w = w;    edge[idx].next = head[u];    head[u] = idx++;    edge[idx].u = v;    edge[idx].v = u;    edge[idx].w = 0;    edge[idx].next = head[v];    head[v] = idx++;}int SAP(int s, int e){    int max_flow = 0, v, u = s;    int id, mindis;    aug[s] = oo;    pre[s] = -1;    memset(dis, 0, sizeof(dis));    memset(gap, 0, sizeof(gap));    gap[0] = n; // 我觉得这一句要不要都行,因为dis[e]始终为0    for (int i = 0; i <= n; ++i)    {   // 初始化当前弧为第一条弧        cur[i] = head[i];    }    while (dis[s] < n)    {        bool flag = false;        if (u == e)        {            max_flow += aug[e];            for (v = pre[e]; v != -1; v = pre[v]) // 路径回溯更新残留网络            {                id = cur[v];                edge[id].w -= aug[e];                edge[id^1].w += aug[e];                aug[v] -= aug[e]; // 修改可增广量,以后会用到                if (edge[id].w == 0) u = v; // 不回退到源点,仅回退到容量为0的弧的弧尾            }        }        for (id = cur[u]; id != -1; id = edge[id].next)        {   // 从当前弧开始查找允许弧            v = edge[id].v;            if (edge[id].w > 0 && dis[u] == dis[v] + 1) // 找到允许弧            {                flag = true;                pre[v] = u;                cur[u] = id;                aug[v] = min(aug[u], edge[id].w);                u = v;                break;            }        }        if (flag == false)        {            if (--gap[dis[u]] == 0) break; /* gap优化,层次树出现断层则结束算法 */            mindis = n;            cur[u] = head[u];            for (id = head[u]; id != -1; id = edge[id].next)            {                v = edge[id].v;                if (edge[id].w > 0 && dis[v] < mindis)                {                    mindis = dis[v];                    cur[u] = id; // 修改标号的同时修改当前弧                }            }            dis[u] = mindis + 1;            gap[dis[u]]++;            if (u != s) u = pre[u]; // 回溯继续寻找允许弧        }    }    return max_flow;}int main(){    while (scanf("%d %d", &n, &m) != EOF)    {        int a, b, w;        memset(head, -1, sizeof(head));        idx = 0;        for (int i = 1; i <= n; ++i)        {            scanf("%d %d", &a, &b);            addEdge(0, i, a);            addEdge(i, n + 1, b);        }        for (int i = 0; i < m; ++i)        {            scanf("%d %d %d", &a, &b, &w);            addEdge(a, b, w);            addEdge(b, a, w);        }        n += 2;        printf("%d\n", SAP(0, n - 1));    }    return 0;}

原创粉丝点击