图论——网络流

首先先上一个自己觉的非常ok的博客:大佬的博客

这里我觉的要讲的是这个算法的主要组件:链式前向星,deep数组,前者用来存图,后者用来记录每个点的深度(方便dfs搜索)

来个板子题:洛谷P1343

#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
const int maxn = 300;
int n;    //网络流的终点是n 
int cnt; //链式前向星的组件 

int deep[maxn]; // 记录点的深度 
int head[maxn];
struct node{
    int u, v, w, next;
}edge[maxn*30];

void add(int u, int v, int w){
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

int bfs()
{
    memset(deep, -1, sizeof(deep));//初始化为-1,因为每次因为前面进行了一次dfs,每个点的w值都会发生变化 
    deep[1] = 0;    //起始点1的深度为0 
    queue<int> q;
    q.push(1);
    while(q.size())
    {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = edge[i].next)
        {
            int v = edge[i].v;
            if(deep[v] == -1 && edge[i].w > 0)//如果说这个v点没有被访问,并且他还可以有余量就放到dfs的搜索编号中 
            {
                deep[v] = deep[u]+1;//深度+1,继续bfs    
                q.push(v);
            }    
        }
    }
    return deep[n] != -1; //如果deep【n】为-1,很有可能中间的某个路是0,导致不能再继续到达n点,返回0 
}

int dfs(int u, int all)//当前点是u, 他剩下给他的子树的余量是all 
{
    if(u == n)
        return all;
    int all1 = all;
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].v;
        if(deep[v] == deep[u] + 1 && edge[i].w > 0)//是下一个深度的点,并且他有余量 
        {
            int d = dfs(v, min(all, edge[i].w));//父亲的余量和自己的最大的通过量的最小化 
            all -= d;    //更新残量,为u的下一个连接点做准备 
            edge[i].w -= d; 
            edge[i^1].w += d;
            if(all == 0) //如果全部用完了,也没有继续搜索下去的必要了 
                break;
        }
    }
    return all1 - all;//返回使用的量 
}

int dinic()
{
    int ans = 0;
    while(bfs())
    {
        ans += dfs(1, 1e9);    
    }    
    return ans;
} 

void ini()
{
    cnt = 0;
    for(int i = 0; i < maxn; i++)
        head[i] = -1;    
}
int main()
{
    int m, x;
    cin >> n >> m >> x;
    int u, v, w;
    ini();
    for(int i = 0; i < m; i++)
    {
        cin >> u >> v >> w;
        add(u, v, w);
        add(v, u, 0);
    }
    int ans = dinic();
    if(ans == 0)
        printf("Orz Ni Jinan Saint Cow!\n");
    else 
    {
        if(x%ans)    printf("%d %d\n", ans, x/ans+1);
        else printf("%d %d\n", ans, x/ans);
    }
    return 0;
}

 再来一个POJ练习下:POJ1459Power Network

注意这个题目你会发现其实是多源点,多汇点的,但是其实只要自己在设置一个超级源点,连接多源点,设置一个超级汇点,连接多个汇点就好了

#include<iostream>
#include<string>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 200;

int sta, end;
int cnt;
int head[maxn];
int map[maxn][maxn];
struct node{
    int u, v, w, next;
}edge[maxn*maxn];

void add(int u, int v, int w)
{
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];    
    map[u][v] = cnt;
    head[u] = cnt++;
}

int deep[maxn];
int bfs()
{
    memset(deep, -1, sizeof(deep));
    queue<int> q;
    deep[sta]  = 0;
    q.push(sta);
    while(q.size())
    {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = edge[i].next)
        {
            int v = edge[i].v;
            if(deep[v] == -1 && edge[i].w > 0)
            {
                deep[v] = deep[u] + 1;
                q.push(v);    
            }
        }
    }
    return deep[end] != -1;
}

int dfs(int u, int all)
{
    if(u == end)
        return all;
    int all1 = all;
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].v;
        if(deep[v] == deep[u] + 1 && edge[i].w > 0)
        {
            int d = dfs(v, min(edge[i].w, all));
            all -=d;
            edge[i].w -= d;
            edge[i^1].w += d;
            if(all == 0)
                break;
        }
    }
    return all1 - all;
}

int dinic()
{
    int ans = 0;
    while(bfs())
    {
        ans += dfs(sta, 1e9);
    }
    return ans;
}
void ini()
{
    memset(map, 0, sizeof(map));
    for(int i = 0; i < maxn; i++)
        head[i] = -1;
    cnt = 0;
}

int main()
{
    int n, np, nc, m;
    while(cin >> n >> np >> nc >> m)
    {
        int u, v, w;
        ini();
        for(int i = 0 ; i < m; i++)
        {
            scanf(" (%d,%d)%d", &u, &v, &w);
            if(map[u][v])
            {
                edge[map[u][v]].w += w; 
            }
            else if(map[v][u])
            {
                edge[map[v][u]^1].w += w;
            }
            else 
            {
                add(u, v, w);
                add(v, u, 0);
            }
        }
        sta = n, end = n+1;
        u = sta;
        for(int i = 0; i < np; i++)
        {
            scanf(" (%d)%d", &v, &w);
            if(map[u][v])
            {
                edge[map[u][v]].w += w; 
            }
            else if(map[v][u])
            {
                edge[map[v][u]^1].w += w;
            }
            else 
            {
                add(u, v, w);
                add(v, u, 0);
            }
        }
        v = end;
        for(int i = 0; i < nc; i++)
        {
            scanf(" (%d)%d", &u, &w);
            if(map[u][v])
            {
                edge[map[u][v]].w += w; 
            }
            else if(map[v][u])
            {
                edge[map[v][u]^1].w += w;
            }
            else 
            {
                add(u, v, w);
                add(v, u, 0);
            }
        }

        printf("%d\n", dinic());
    }
    
    
    
    return 0;
}

 

posted @ 2020-10-10 17:36  斌斌翻水水  阅读(70)  评论(1)    收藏  举报