网络流dinic与EK

题目链接:网络流

EK算法核心思想

EK算法是Ford-Fulkerson方法的一种实现,使用BFS来寻找增广路径,用于求解最大流问题

算法步骤:

  1. 初始化

    • 构建残量网络,初始时正向边容量为原容量,反向边容量为0
    • 最大流初始为0
  2. 循环寻找增广路径

    • 使用BFS在残量网络中寻找从源点s到汇点t的路径
    • 记录路径上的最小容量(瓶颈容量)
  3. 更新残量网络

    • 沿着找到的增广路径,正向边减去流量,反向边加上流量
    • 将瓶颈容量加到最大流中
  4. 重复直到找不到增广路径

核心代码:

bool E_K_bfs(){
    memset(vis,-1,sizeof(vis));pre[s]=-1;
    vis[s]=1;
    myline.push(s); minroad[s]=INT_MAX;
    
    while(!myline.empty()){
        int u=myline.front();myline.pop();vis[u]=0;
        for(int i=head[u];i;i=q[i].link){
            int v=q[i].v,w=q[i].w;
            if(w){  // 只有残量>0的边才考虑
                if(~vis[v]) continue;  // 已访问过则跳过
                minroad[v]=min(minroad[u],w);  // 记录路径最小容量
                pre[v]=i;  // 记录到达v的边
                myline.push(v);
                vis[v]=u;  // 标记已访问            
            }
        }
    }
    if(vis[t]!=-1) return true;  // 找到增广路径
    return false;
}

void update(){
    int now=t;
    while(now!=s){
        int id=pre[now];
        q[id].w -= minroad[t];  // 正向边减去流量
        q[id^1].w += minroad[t];  // 反向边增加流量
        now = q[id^1].v;  // 回溯到前一个节点
    }
    maxflow += minroad[t];  // 增加总流量
}

关键特点:

  1. 链式前向星存图cnt从1开始,方便用^1获取反向边
  2. 残量网络:正向边存剩余容量,反向边存已用容量
  3. BFS寻路:保证找到的是最短增广路径
  4. 反向边机制:允许"反悔",这是最大流算法的核心

时间复杂度:

  • O(VE²),其中V是节点数,E是边数
  • 每次BFS:O(E)
  • 最多进行O(VE)次BFS

算法正确性保证:

  1. 增广路定理:当且仅当残量网络中不存在s-t路径时,当前流是最大流
  2. 最短路径增长:每次找到最短增广路,保证算法终止
  3. 反向边:确保能找到全局最优解

与相关算法对比:

算法时间复杂度特点
EKO(VE²)实现简单,适合稀疏图
DinicO(V²E)分层图+多路增广,效率更高
ISAPO(V²E)改进的Dinic,常数更小

总结:EK算法通过不断在残量网络中寻找增广路径并更新流量,最终得到最大流。

#include<bits/stdc++.h>
#include<queue>
using namespace std;

const int N=1000101;
int n,m,s,t,cnt=1;int head[N];
int vis[N];
//int vis[N];
int pre[N],minroad[N];
queue <int> myline;
struct edge{
	int v,w,link,u;
}q[N<<2];

void put(int x,int y,int z){
	q[++cnt].v=y,q[cnt].u=x,q[cnt].w=z,q[cnt].link=head[x],head[x]=cnt;
	q[++cnt].v=x,q[cnt].u=y,q[cnt].w=0,q[cnt].link=head[y],head[y]=cnt;
}

bool E_K_bfs(){
	memset(vis,-1,sizeof(vis));pre[s]=-1;
	vis[s]=1;
	myline.push(s);	minroad[s]=INT_MAX;
	while(!myline.empty()){
		int u=myline.front();myline.pop();vis[u]=0;
		for(int i=head[u];i;i=q[i].link){//	puts("check");
			int v=q[i].v,w=q[i].w;
			if(w){
			if(~vis[v]) continue;	
			minroad[v]=min(minroad[u],w);
			pre[v]=i;
			myline.push(v);
			vis[v]=u;			
		//	printf("v:%dminroad:%d",v,minroad[v]);
		}
		}
	}//puts("check");
	if(vis[t]!=-1){	return true;}
	return false;
}

int maxflow=0;
void update()
{
//	puts("checkgood");
	int now=t;
	while(now!=s){
		int id=pre[now];
		q[id].w-=minroad[t];
		q[id^1].w+=minroad[t];
		now=q[id^1].v;
	}
	maxflow+=minroad[t];
}
int main(){
    //freopen("tt.txt","r",stdin);
    //freopen("tt.out","w",stdout);
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		put(u,v,w);
	}
	while(E_K_bfs()) update();
	printf("%d",maxflow);
}

Dinic算法核心思想

Dinic算法是分层图+多路增广的网络流算法,比EK算法效率更高。

算法步骤:

  1. BFS构建分层图

    • 从源点s开始进行BFS
    • 记录每个节点到源点的最短距离(层数)
    • 只考虑残量>0的边
  2. DFS多路增广

    • 在分层图上进行DFS
    • 只向下一层的节点推进
    • 一次DFS可以找到多条增广路
  3. 重复直到无法构建分层图

核心代码:

bool bfs(){
    for(int i=1;i<=n;i++) deep[i]=MAX+5,vis[i]=0,cur[i]=head[i];
    deep[s]=0;
    while(!myline.empty()) myline.pop();
    myline.push(s);vis[s]=1;
    
    while(!myline.empty()){
        int u=myline.front();myline.pop();
        for(int i=head[u];i;i=q[i].link){
            int v=q[i].v;ll w=q[i].w;
            if(vis[v]||(!w)) continue;  // 已访问或残量为0
            if(deep[v]>MAX){  // 未访问过
                deep[v]=deep[u]+1;  // 记录层数
                myline.push(v);
                vis[v]=1;
            }
        }
    }
    if(deep[t]<MAX) return true;  // 能到达汇点
    return false; 
}

BFS作用:构建分层图,deep[i]表示节点i的层数

int dfs(ll limit,int st){
    if(!limit||st==t) return limit;  // 无流量或到达汇点
    ll flow=0,f;
    for(int i=cur[st];i;i=q[i].link){
        cur[st]=i;  // 当前弧优化
        int v=q[i].v;ll w=q[i].w;
        if(deep[v]==deep[st]+1&&(f=dfs(min(limit,w),v))){
            flow+=f;
            limit-=f;
            q[i].w-=f;
            q[i^1].w+=f;
            if(limit<0) return limit;
        }
    }
    return flow;
}

DFS特点

  • 多路增广:一次DFS可能找到多条路径
  • 当前弧优化:cur[st]避免重复检查无效边
  • 分层限制:deep[v]==deep[st]+1确保向下一层推进

Dinic算法的关键优化:

  1. 分层图:避免DFS绕远路
  2. 多路增广:一次DFS找到多条增广路
  3. 当前弧优化:避免重复检查已经"榨干"的边

时间复杂度:

  • O(V²E),比EK的O(VE²)更优
  • 对于单位容量图: O ( m i n ( V 2 / 3 , E 1 / 2 ) × E ) O(min(V^{2/3}, E^{1/2}) × E) O(min(V2/3,E1/2)×E)

与EK算法对比:

特性EK算法Dinic算法
寻路方式BFS单路增广BFS分层 + DFS多路增广
时间复杂度O(VE²)O(V²E)
实际效率较慢快很多
代码复杂度简单中等

代码中的关键点:

  1. 链式前向星cnt从1开始,方便反向边操作
  2. 当前弧优化cur[i]数组,避免重复检查
  3. 分层图deep[i]记录节点层数
  4. 多路增广:DFS中flow+=f累计多条路径

算法正确性保证:

  1. 分层图性质:确保找到的增广路是最短的
  2. 多路增广:充分利用每次BFS构建的分层图
  3. 当前弧优化:不影响正确性,只提升效率

总结:Dinic算法通过分层图限制DFS方向,配合多路增广和当前弧优化,大幅提升了网络流算法的效率

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e4+5,M=1e5+5;
const ll MAX=123456789000;
int n,m,s,t;ll w;
queue<int > myline;
int head[N],cur[N],cnt=1;
ll deep[N];
struct edge{
	int link,v,u;
	ll w;
}q[M<<1];
bool vis[N];
void put(int u,int v,ll w){q[++cnt].v=v,q[cnt].u=u,q[cnt].w=w;q[cnt].link=head[u],head[u]=cnt;}
bool bfs(){
	for(int i=1;i<=n;i++) deep[i]=MAX+5,vis[i]=0,cur[i]=head[i];
	deep[s]=0;
	while(!myline.empty()) myline.pop();
	myline.push(s);vis[s]=1;
	while(!myline.empty()){
         int u=myline.front();myline.pop();
   		for(int i=head[u];i;i=q[i].link){
   			int v=q[i].v;ll w=q[i].w;
   			if(vis[v]||(!w)) continue;
   			if(deep[v]>MAX){
   				deep[v]=deep[u]+1;
   				myline.push(v);
   				vis[v]=1;
   			}
   		}
	}
	if(deep[t]<MAX) return true;
	return false; 
}
int dfs(ll limit,int st){
	if(!limit||st==t) return limit;
	ll flow=0,f;
	for(int i=cur[st];i;i=q[i].link){
		cur[st]=i;
		int v=q[i].v;ll w=q[i].w;
		if(deep[v]==deep[st]+1&&(f=dfs(min(limit,w),v))){
			flow+=f;
			limit-=f;
			q[i].w-=f;
			q[i^1].w+=f;
			if(limit<0) return limit;
		}
	}
	return flow;
}
void Dinic(){
	ll ff=0;
	while(bfs()){
//		for(int i=1;i<=n;i++){
//			printf("deep[%d]=%lld ",i,deep[i]);
//		}
//		puts("");
		ff=ff+dfs(MAX,s);
	} 
	printf("%lld",ff);
}
int main(){
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++){
		int u,v;ll w;
		scanf("%d%d%lld",&u,&v,&w);
		put(u,v,w),put(v,u,0);
	}
	Dinic();
}
内容概要:本文介绍了ENVI Deep Learning V1.0的操作教程,重点讲解了如何利用ENVI软件进行深度学习模型的训练应用,以实现遥感图像中特定目标(如集装箱)的自动提取。教程涵盖了从数据准备、标签图像创建、模型初始化训练,到执行分类及结果优化的完整流程,并介绍了精度评价通过ENVI Modeler实现一键化建模的方法。系统基于TensorFlow框架,采用ENVINet5(U-Net变体)架构,支持通过点、线、面ROI或分类图生成标签数据,适用于多/高光谱影像的单一类别特征提取。; 适合人群:具备遥感图像处理基础,熟悉ENVI软件操作,从事地理信息、测绘、环境监测等相关领域的技术人员或研究人员,尤其是希望将深度学习技术应用于遥感目标识别的初学者实践者。; 使用场景及目标:①在遥感影像中自动识别和提取特定地物目标(如车辆、建筑、道路、集装箱等);②掌握ENVI环境下深度学习模型的训练流程关键参数设置(如Patch Size、Epochs、Class Weight等);③通过模型调优结果反馈提升分类精度,实现高效自动化信息提取。; 阅读建议:建议结合实际遥感项目边学边练,重点关注标签数据制作、模型参数配置结果后处理环节,充分利用ENVI Modeler进行自动化建模参数优化,同时注意软硬件环境(特别是NVIDIA GPU)的配置要求以保障训练效率。
内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略效果评估体系,涵盖当前企业传播面临的预算、资源、内容效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户和自媒体四类媒体资源的特性、传播优势发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放GEO优化,提升品牌在AI搜索中的权威性可见性;④通过数据驱动评估体系量化品牌影响力销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析工具指南进行系统学习,重点关注媒体适配性策略GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值