hdu 1532 Drainage Ditches && hdu 3549 Flow Problem 网络流最大流问题 Edmonds-Karp算法

本文详细介绍了EK算法在网络流问题中的应用,包括如何通过不断寻找增广路径来求解最大流问题,并给出了两个具体实例的代码实现。

看了好几天最大流的EK算法了,到今天才总算想明白,趁热打铁写个总结巩固一下。

网络流中的最大流问题指的是给你一个网络,让你求出这个网络中从源点到汇点的最大流量

可以将其看成管道,每个管道有一个容量和流量,同时有一个残余流量的概念。

比如,设有一条边 u->v ;用 c [u,v] 表示这条边的容量,f [u,v] 表示这条路的流量,则这条边的残余流量 r [u,v] = c [u,v] - f [u,v] ;

EK算法的核心,就是不断地寻找增广路。这里的增广路指的是从源点到汇点的一条可行路,即其中每条边的残余流量均大于0;

当不能再找到增广路时,算法结束,此时源点到汇点之间再没有可行路了,显然流量已经达到了最大值。

通俗一点讲,就是再没有一条路从源点到汇点了,那么自然没有更多流量可以流入到汇点了。

算法的基本思路:通过BFS寻找增广路,每次寻找一条并由此更新整个网络中的残余流量,直至无法找到增广路为止。

hdu 的1532 和 3549 都是模板题,可以拿来练手,附上代码,有注释帮助理解。

hdu 1532
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define S 210
#define maxn 0xfffffff
int c[S][S];                                                      //这里表示残余流量
int pre[S],flow[S];                                               //前驱、到某个点的流量
int N,M;                                                          //此题中 M 即为汇点
queue<int>q;
int bfs()
{
    memset(pre,-1,sizeof(pre));
    while(!q.empty()) q.pop();
    flow[1]=maxn;                                                 //源点视为无限流出
    q.push(1);                                                    //源点入列
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        if(now==M) break;                                         //当前点为汇点时意味着寻找增广路结束
        for(int i=1;i<=M;i++)
        {
            if(i!=1&&c[now][i]>0&&pre[i]==-1)                     //回流到源点无意义,此题中 1 为源点
            {                                                     //残余流量必须大于0,同时前驱要求为-1,因为算法每次只寻找一条增广路
                pre[i]=now;                                       //若该点前驱不为-1意味着已经找到了一条从某个点到该点的增广路,
                flow[i]=min(flow[now],c[now][i]);                 //寻找增广路中允许通过的最大流量
                q.push(i);                                        //该点入列
            }
        }
    }
    if(pre[M]==-1) return -1;                                     //没有前驱意味着没有找到可行的增广路,返回-1
    return flow[M];
}
int maxflow()
{
    int add=0,sum=0;
    while((add=bfs())!=-1)                                        //add为增广路中可增加的流量,即该条增广路允许的最大流量
    {
        int k=M;
        while(k!=1)                                               //1为源点,利用前驱更新增广路中的残余流量
        {
            c[pre[k]][k]-=add;
            c[k][pre[k]]+=add;                                    //反向边
            k=pre[k];
        }
        sum+=add;
    }
    return sum;
}
int main()
{
    while(~scanf("%d%d",&N,&M))
    {
        memset(c,0,sizeof(c));
        memset(flow,0,sizeof(flow));
        int from,to,cap;
        for(int i=0;i<N;i++)
        {
            scanf("%d%d%d",&from,&to,&cap);
            c[from][to]+=cap;                                     //注意可能有重边,多条从某个点到另一点的边可将它们相加
        }
        cout<<maxflow()<<endl;
    }
}

hdu 3549
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define S 20
int N,M,c[S][S],flow[S],pre[S];
queue<int>q;
int bfs()
{
    while(!q.empty()) q.pop();
    memset(pre,-1,sizeof(pre));
    flow[1]=0xfffffff;
    q.push(1);
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        if(now==N) break;
        for(int i=1;i<=N;i++)
        {
            if(i!=1&&c[now][i]>0&&pre[i]==-1)
            {
                pre[i]=now;
                flow[i]=min(flow[now],c[now][i]);
                q.push(i);
            }
        }
    }
    if(pre[N]==-1) return -1;
    return flow[N];
}
int maxflow()
{
    int sum=0,add=0;
    while((add=bfs())!=-1)
    {
        int k=N;
        while(k!=1)
        {
            c[pre[k]][k]-=add;
            c[k][pre[k]]+=add;
            k=pre[k];
        }
        sum+=add;
    }
    return sum;
}
int main()
{
    int T;
    cin>>T;
    int K=0;
    while(T--)
    {
        scanf("%d%d",&N,&M);
        memset(c,0,sizeof(c));
        memset(flow,0,sizeof(flow));
        int x,y,cap;
        for(int i=0;i<M;i++)
        {
            scanf("%d%d%d",&x,&y,&cap);
            c[x][y]+=cap;
        }
        printf("Case %d: %d\n",++K,maxflow());
    }
}


关于其中反向边的问题,记得看到过一句话:反向边就是给程序一个反悔的机会。

推荐一个博客,可供参考:传送门


基于STM32 F4的永磁同步电机无位置传感器控制策略研究内容概要:本文围绕基于STM32 F4的永磁同步电机(PMSM)无位置传感器控制策略展开研究,重点探讨在不依赖物理位置传感器的情况下,如何通过算法实现对电机转子位置和速度的精确估计与控制。文中结合嵌入式开发平台STM32 F4,采用如滑模观测器、扩展卡尔曼滤波或高频注入法等先进观测技术,实现对电机反电动势或磁链的估算,进而完成无传感器矢量控制(FOC)。同时,研究涵盖系统建模、控制算法设计、仿真验证(可能使用Simulink)以及在STM32硬件平台上的代码实现与调试,旨在提高电机控制系统的可靠性、降低成本并增强环境适应性。; 适合人群:具备一定电力电子、自动控制理论基础和嵌入式开发经验的电气工程、自动化及相关专业的研究生、科研人员及从事电机驱动开发的工程师。; 使用场景及目标:①掌握永磁同步电机无位置传感器控制的核心原理与实现方法;②学习如何在STM32平台上进行电机控制算法的移植与优化;③为开发高性能、低成本的电机驱动系统提供技术参考与实践指导。; 阅读建议:建议读者结合文中提到的控制理论、仿真模型与实际代码实现进行系统学习,有条件者应在实验平台上进行验证,重点关注观测器设计、参数整定及系统稳定性分析等关键环节。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值