HDU 3549 Flow Problem(网络流 ,FF EK Dinic)

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

这个是网络流 最大流 的模板题,

存个模板

Ford-Fulkerson

//Ford-Fulkerson
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a));
#define pb push_back
#define mp make_pair
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> p;
const int inf=0x3f3f3f3f;
const int maxn=20;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
const double e=2.718281828459;
void fre()
{
    freopen("in.txt","t",stdin);
}
int t,n,m,x,y,c;
//起点、终点
int st,en;
//增广路经流量
int flow;
//最大流结果
int ans;
//顶点标记数组
bool vis[maxn];
//残留网
int maze[maxn][maxn];
//dfs寻找增广路经
int dfs(int u,int FindFlow)
{
    //若知道汇点返回此增广路经中
    if(u==en) return FindFlow;
    if(vis[u]) return 0;
    //标记此顶点为已访问点
    vis[u]=1;
    //枚举寻找下一个顶点
    for(int i=1;i<=n;i++)
    {
        //跳过两顶点之间容量为0的顶点
        if(maze[u][i])
        {
            //从i点寻找路经,并返回路经流量
            int LastLineFlow=dfs(i,FindFlow<maze[u][i]?FindFlow:maze[u][i]);
            //跳过路经流量为0的点
            if(LastLineFlow==0)
                continue;
            //找到增广路经后更新残留网
            maze[u][i]-=LastLineFlow;
            maze[i][u]+=LastLineFlow;
            //返回此增广路经的流量
            return LastLineFlow;
        }
    }
    //若未找到增广路经则返回0
    return 0;
}
int maxflow(int st,int en)
{
    int ans=0;
    while(flow=dfs(st,inf))//不断寻找增广路经
    {
        ans+=flow;//增加流量
        mem(vis,0);
    }
    return ans;
}
int main()
{
    //fre();
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        mem(vis,0);
        mem(maze,0);
        scanf("%d%d",&n,&m);
        st=1,en=n;
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&c);
            //这道题有重边所以写+=
            maze[x][y]+=c;
        }

        printf("Case %d: %d\n",i,maxflow(1,n));
    }return 0;
}

EK算法

/*
EK算法 核心
反复寻找源点s到汇点t之间的增广路经,若有找出增广路经上
每一段[容量-流量]的最小值delta,若无则结束
在寻找增广路经时,可以用BFS来找,并且更新残留网络的值(涉及到反向边)
而找到delta后,则使最大流加上delta更新为当前的最大流值
*/
#include <bits/stdc++.h>
using namespace std;
#define arraysize 205
int maxData=0x3f3f3f3f;
int capacity[arraysize][arraysize];//记录残留网络的容量
int flow[arraysize];//记录从源点到当前节点实际还剩多少流量可用
int pre[arraysize];//标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
int n,m;
queue<int > myqueue;
int BFS(int src,int des)
{
    int i,j;
    while(!myqueue.empty())
        myqueue.pop();
    memset(pre,-1,sizeof(pre));
    pre[src]=0;
    flow[src]=maxData;
    myqueue.push(src);
    while(!myqueue.empty())
    {
        int index=myqueue.front();
        myqueue.pop();
        if(index==des)//找到了增广路经
            break;
        for(int i=1;i<=n;i++)
        {
            if(i!=src&&capacity[index][i]>0&&pre[i]==-1)
            {
                pre[i]=index;//记录前驱
                flow[i]=min(capacity[index][i],flow[index]);//迭代的找到增量 关键
                myqueue.push(i);
            }
        }
    }
    if(pre[des]==-1)//残留图中不再存在增广路经
        return -1;
    else return flow[des];
}
int maxFlow(int src,int des)
{
    int increasement=0;
    int sumflow=0;
    while((increasement=BFS(src,des)!=-1))
    {
        int k=des;
        while(k!=src)
        {
            int last=pre[k];
            capacity[last][k]-=increasement;//改变正向边的容量
            capacity[k][last]+=increasement;//改变反向边的容量
            k=last;

        }
        sumflow+=increasement;
    }return sumflow;
}
int main()
{
    int i,j,t;
    int st,en,ci;
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        cin>>n>>m;
        memset(capacity,0,sizeof(capacity));
        memset(flow,0,sizeof(flow));
        for(int i=0;i<m;i++)
        {
            cin>>st>>en>>ci;
            if(st==en)//考虑起点终点相同的情况
            continue;
            capacity[st][en]+=ci;
            //此处注意可能出现多条同一起点终点的情况
        }
        cout<<"Case "<<i<<": "<<maxFlow(1,n)<<endl;
    }

    return 0;
}
/*AC*/

Dinic算法

#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxx=305;
int n,m,c[maxx][maxx],dep[maxx];
//dep代表当前层数
int bfs(int s,int t)//重新建图,按层次建图
{
    queue<int >q;
    while(!q.empty())
     q.pop();
    memset(dep,-1,sizeof(dep));
    dep[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int v=1;v<=n;v++)
        {
            if(c[u][v]>0&&dep[v]==-1)//如果可以到达且没有访问,可以到达的条件是剩余容量大于0 没有访问的条件是当前层数还未知
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    if(dep[t]==-1) return 0;//深度不存在时 不存在分层图
    return 1;
}
int dfs(int u,int flow,int t)//查找路经上的最小流量
{
    if(u==t)
        return flow;
    int temp;
    for(int i=1;i<=n;i++)
    {
        if(c[u][i]>0&&(dep[i]=dep[u]+1)&&(temp=dfs(i,min(flow,c[u][i]),t)))
        {
            c[u][i]-=temp;
            c[i][u]+=temp;
            return temp;
        }
    }return 0;
}
int dinic()
{
    int ans=0,temp;
    while(bfs(1,n))
    {
        while(1)
        {
            temp=dfs(1,inf,n);
            if(temp==0)
                break;
            ans+=temp;
        }
    }return ans;
}
int main()
{
    int t;
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        memset(c,0,sizeof(c));
        int u,v,w;
        cin>>n>>m;
        while(m--)
        {
            cin>>u>>v>>w;
            c[u][v]+=w;
        }
        cout<<"Case "<<i<<": "<<dinic()<<endl;
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40046426/article/details/81809369