码迷,mamicode.com
首页 > 编程语言 > 详细

HDU 3549 Flow Problem (用一道最裸的最大流开启网络流算法之路)

时间:2015-04-27 13:17:07      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:hdu   网络最大流   


Flow Problem

Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)

Total Submission(s): 9423    Accepted Submission(s): 4405



Problem Description
Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph.
 

Input
The first line of input contains an integer T, denoting the number of test cases.
For each test case, the first line contains two integers N and M, denoting the number of vertexes and edges in the graph. (2 <= N <= 15, 0 <= M <= 1000)
Next M lines, each line contains three integers X, Y and C, there is an edge from X to Y and the capacity of it is C. (1 <= X, Y <= N, 1 <= C <= 1000)
 

Output
For each test cases, you should output the maximum flow from source 1 to sink N.
 

Sample Input
2 3 2 1 2 1 2 3 1 3 3 1 2 1 2 3 1 1 3 1
 

Sample Output
Case 1: 1 Case 2: 2
 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549

题目大意:就是求源点为1,汇点为n的网络最大流

题目分析:博客以前有写过几道最大流的题目,可是用的是EK算法,EK这个算法已经可以被淘汰了,因为它的时间复杂度太高,这题用EK搞要2000ms+,EK算法就不贴了,下面主要提到sap里的两个主流算法,dinic和isap算法,这两个算法在求解这道题上时间相当,都是150ms左右,但实际上isap的效率是比dinic高的,关于dinic和isap算法的介绍会在别的文章里阐述,这里就贴一下模板

Dinic 1: 隐性层次网
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int const MAX = 16;
int const INF = 0x3fffffff;

int cap[MAX][MAX];
int d[MAX];
int n, m;

bool BFS()
{
    memset(d, 0, sizeof(d));
    queue <int> Q;
    d[1] = 0;
    Q.push(1);
    while(!Q.empty())
    {
        int cur = Q.front();
        Q.pop();
        for(int i = 2; i <= n; i++)
        {
            if(cap[cur][i] > 0 && d[i] == 0)
            {
                d[i] = d[cur] + 1;
                Q.push(i);
            }
        }
    }
    return d[n];
}

int Dinic(int t, int flow)
{
    if(t == n)
        return flow;
    int tmp = flow;
    for(int i = 1; i <= n; i++)
    {
        if(d[i] == d[t] + 1 && cap[t][i] > 0)
        {
            int mi = Dinic(i, min(flow, cap[t][i]));
            cap[t][i] -= mi;
            cap[i][t] += mi;
            flow -= mi;
        }
    }
    return tmp - flow;
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ca++)
    {
        memset(cap, 0, sizeof(cap));
        scanf("%d %d", &n, &m);
        for(int i = 0; i < m; i++)
        {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            cap[u][v] += w;
        }
        int ans = 0;
        while(BFS())
            ans += Dinic(1, INF);
        printf("Case %d: %d\n", ca, ans);
    }
}


Dinic 2:  显性层次网
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int const MAX = 20;
int const INF = 0x3fffffff;

int cap[MAX][MAX];
bool sign[MAX][MAX], vis[MAX];
int d[MAX];
int n, m;

bool BFS()
{
    memset(vis, false, sizeof(vis));
    memset(sign, false, sizeof(sign));
    queue <int> Q;
    d[1] = 0;
    Q.push(1);
    while(!Q.empty())
    {
        int cur = Q.front();
        Q.pop();
        for(int i = 2; i <= n; i++)
        {
            if(!vis[i] && cap[cur][i])
            {
                vis[i] = true;
                sign[cur][i] = true;
                Q.push(i);
            }
        }                                      
    }
    return vis[n];
}

int Dinic(int t, int flow)
{
    if(t == n)
        return flow;
    int tmp = flow;
    for(int i = 2; i <= n; i++)
    {
        if(sign[t][i])
        {
            int mi = Dinic(i, min(flow, cap[t][i]));
            cap[t][i] -= mi;
            cap[i][t] += mi;
            flow -= mi;
        }
    }
    return tmp - flow;
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ca++)
    {
        memset(cap, 0, sizeof(cap));
        scanf("%d %d", &n, &m);
        for(int i = 0; i < m; i++)
        {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            cap[u][v] += w;
        }
        int ans = 0;
        while(BFS())
            ans += Dinic(1, INF);
        printf("Case %d: %d\n", ca, ans);
    }
}


ISAP:
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
int const INF = 0x3fffffff;
int const MAXN = 2000;
int const MAXM = 2000;
int head[MAXN], gap[MAXN], d[MAXN], cur[MAXN], pre[MAXN];
int n, m, e_cnt;

struct EDGE
{
    int to, cap, flow, next;
}e[MAXM];

void Add_Edge(int u, int v, int cap)
{
    e[e_cnt].to = v;
    e[e_cnt].cap = cap;
    e[e_cnt].flow = 0;
    e[e_cnt].next = head[u];
    head[u] = e_cnt ++;

    e[e_cnt].to = u;
    e[e_cnt].cap = 0;
    e[e_cnt].flow = 0;
    e[e_cnt].next = head[v];
    head[v] = e_cnt ++;
}

void BFS(int t)
{
    queue <int> Q;
    memset(gap, 0, sizeof(gap));
    memset(d, -1, sizeof(d));
    d[t] = 0;
    Q.push(t);
    while(!Q.empty())
    {
        int v = Q.front();
        Q.pop();
        gap[d[v]] ++;
        for(int i = head[v]; i != -1; i = e[i].next)
        {
            int u = e[i].to;
            if(d[u] == -1)
            {
                d[u] = d[v] + 1;
                Q.push(u);
            }
        }
    }
}

int ISAP(int s, int t)
{
    BFS(t);
    int ans = 0, u = s, flow = INF;
    memcpy(cur, head, sizeof(cur));
    while(d[s] < e_cnt)
    {
        int i = cur[u];
        for(; i != - 1; i = e[i].next)
        {
            int v = e[i].to;
            if(e[i].cap > e[i].flow && d[u] == d[v] + 1)
            {
                u = v;
                pre[v] = i;
                flow = min(flow, e[i].cap - e[i].flow);
                if(u == t)
                {
                    while(u != s)
                    {
                        int j = pre[u];
                        e[j].flow += flow;
                        e[j ^ 1].flow -= flow;
                        u = e[j ^ 1].to;
                    }
                    ans += flow;
                    flow = INF;
                }
                break;
            }
        }
        if(i == -1)
        {
            if(-- gap[d[u]] == 0)
                break;
            int mi = e_cnt - 1;
            cur[u] = head[u];
            for(int j = head[u]; j != -1; j = e[j].next)
                if(e[j].cap > e[j].flow)
                    mi = min(mi, d[e[j].to]);
            d[u] = mi + 1;
            gap[d[u]] ++;
            if(u != s)
                u = e[pre[u] ^ 1].to;
        }
    }
    return ans;
}

int main()
{
    int T, ans;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ca++)
    {
        scanf("%d %d", &n, &m);
        e_cnt = 0;
        memset(head, -1, sizeof(head));
        for(int i = 0; i < m; i++)
        {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            Add_Edge(u, v, w);
        }
        ans = ISAP(1, n);
        printf("Case %d: %d\n", ca, ans);
    }
}



HDU 3549 Flow Problem (用一道最裸的最大流开启网络流算法之路)

标签:hdu   网络最大流   

原文地址:http://blog.csdn.net/tc_to_top/article/details/45308525

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!