Drainage Ditches (Dinic)

47 篇文章 0 订阅
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;


#define INF 0x1f1f1f1f
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define N 500


int cap[N][N];//容量
int flow[N][N];//流量
int lev[N];//层次
bool vis[N];//标记
int que[100000];//队列
//st 小顶点标号,ed 大顶点标号,src 源点标号,tar 汇点标号
bool bfs(int vsta,int vend,int sta,int end)
//st 小点 ed 大点 src 源点 tar 汇点
{
    int front;//队首
    int rear;//队尾
    front=rear=0;
    que[front++]=sta;
    lev[sta]=0;
    memset(vis,0,sizeof(vis));
    vis[sta]=1;
    while(rear<front)
    {
        int t=que[rear++];
        for(int i=vsta; i<=vend; i++)
        {
            if(!vis[i]&&cap[t][i]>flow[t][i])
            {
                vis[i]=1;
                lev[i]=lev[t]+1;
                que[front++]=i;
            }
        }
    }
    return lev[end]<INF;
}
//利用层次网络进行增广,每次 DFS 寻找的是从该节点出发进行 DFS 增加的总流量
int dfs(int v,int vsta,int vend,int end,int fl)
//fl 表示源点到当前顶点的流量
{
    int ret=0;
    if(v==end||fl==0)return fl;
    for(int i=vsta; i<=vend; i++)
    {
        if(fl==0)break;
        if(cap[v][i]>flow[v][i]&&lev[v]+1==lev[i])
        {
            int f=MIN(fl,cap[v][i]-flow[v][i]);//沿 i 点向下可用大流量
            int tt=dfs(i,vsta,vend,end,f); //沿 i 点向下实际增广的流量
            if(tt<=0)continue;
            ret+=tt;
            fl-=tt;//每次修改 fl
            flow[v][i]+=tt;
            flow[i][v]-=tt;
        }
    }
    return ret;
}
int dinic(int vsta,int vend,int sta,int end)
{
    int ret=0;
    while(bfs(vsta,vend,sta,end))//存在可增广路
    {
        int r=dfs(sta,vsta,vend,end,INF);
        if(r==0)break;
        ret+=r;
    }
    return ret;
}




int main()
{


    int n ,m ;
    while(scanf("%d %d",&n, &m) != EOF)
    {
        int u, v, val;
        memset(cap, 0, sizeof(cap));
        memset(flow, 0, sizeof(flow));
        for( int i = 0; i <n; i++)
         {
             scanf("%d %d %d",&u, &v, &val);
             cap[u][v] += val;
         }
        int ans = dinic(1, m, 1, m);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值