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

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);
    }
}
时间: 2024-11-05 18:39:25

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

HDU 3549 Flow Problem ( 最大流 -EK 算法)

C++,G++的读取速度差距也太大了 Flow Problem 题意:n,m表示n个点m条有向带权边 问:从1-n最大流多少 裸最大流,拿来练手,挺不错的 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int N = 210; #define

HDU 3549 Flow Problem 网络最大流问题 Edmonds_Karp算法

题目链接:HDU 3549 Flow Problem Flow Problem Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 8218    Accepted Submission(s): 3824 Problem Description Network flow is a well-known difficult problem f

网络流 HDU 3549 Flow Problem

网络流 HDU 3549 Flow Problem 题目:http://acm.hdu.edu.cn/showproblem.php?pid=3549 用增广路算法进行求解,注意的问题有两个: 1. 每次增广的时候,反向流量也要进行更行,一开始没注意,WA了几次 ORZ 2. 对于输入的数据,容量要进行累加更新. // 邻接矩阵存储 #include <bits/stdc++.h> using namespace std; const int INF = 0x7fffffff; const i

hdu 3549 Flow Problem(最大流模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549 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

hdu 3549 Flow Problem (网络最大流)

Flow Problem Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 6674    Accepted Submission(s): 3112 Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, yo

hdu 3549 Flow Problem 网络流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549 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

hdu 3549 Flow Problem (最大流入门题)

增广路: 1 /************************************************************* 2 题目: Flow Problem(HDU 3549) 3 链接: http://acm.hdu.edu.cn/showproblem.php?pid=3549 4 题意: 给一个单向图,求从1到n的最大流 5 算法: 最大流之增广路(入门) 6 算法思想: 不断用BFS找通路,没每找一条路,记录这条路的最小流, 7 再给这条路上的所有流量减去这个最小值.

HDU 3549 Flow Problem (最大流ISAP)

Flow Problem Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 8199    Accepted Submission(s): 3814 Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, yo

hdu 3549 Flow Problem

Flow Problem 题意:N个顶点M条边,(2 <= N <= 15, 0 <= M <= 1000)问从1到N的最大流量为多少? 分析:直接使用Edmonds_Karp算法即可:下面是对增广路的一些理解和代码的解释: 残量:容量-流量: 增广:求出从源点到汇点的一条道路中所有残量的最小值d,把对应的所有边上的流量增加d,反向边(t->s)流量减少d(反向边的cap其实一直是0,只是flow为负了); 技巧:这次的ins的标号是从0开始的,即tot++,之前我都是++t