POJ 3204 [寻找有效满流边]

本文探讨了一个关于最大流的问题,在给定的有向图中寻找能够通过增加某一边的容量来提升整体运输效率的方法。文章介绍了如何判断哪些边的容量增加可以有效提高最大流值,并提供了一段实现该算法的C++代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:有n个点,m条有向边,0号是生产站点,N-1是接受站点,每条边都有限定的流量,Ikki知道这是一个最大流问题,他求出了其网络的最大流,但是他发现这个网络的最大流值很小,没有运输的效率,他想增加这个值,然而增加这个值的方法也很简单,就是他需要对一些边进行增加容量。然而政府比较穷,他只能增加一条边的容量,问有多少个这样的边。

刚开始傻傻的以为只要是满流边就可以了,看别人的题解都是还得满足另外的条件:能从S走到满流边的from,并且能从满流边的to走到T.

看到一个博客讲的还不错:链接

#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
#define MAX 10000
#define INF 0x1f1f1f1f
using namespace std;
int ss, tt;
int n, m;
int cont;
int head[MAX];
int divv[MAX];
int cur[MAX];
struct edge {
  int from, to, w, next;

}e[510000];

void add(int u, int v, int w) {
  e[cont].from = u;
  e[cont].to = v;
  e[cont].w = w;
  e[cont].next = head[u];
  head[u] = cont++;
}

int makediv() {
  memset(divv, 0, sizeof(divv));
  divv[ss] = 1;
  queue<int> Q;
  Q.push(ss);
  while (!Q.empty()) {
    int u = Q.front();
    if (u == tt)
      return 1;
    Q.pop();
    for (int i = head[u]; i != -1; i = e[i].next) {
      int w = e[i].w;
      int v = e[i].to;
      if (divv[v] == 0 && w) {
        divv[v] = divv[u] + 1;
        Q.push(v);
      }
    }

  }
  return 0;

}

int DFS(int u, int maxflow, int tt) {
  if (u == tt)
    return maxflow;
  int ret = 0;
  for (int &i = cur[u]; i != -1; i = e[i].next) {
    int v = e[i].to;
    int w = e[i].w;
    if (divv[v] == divv[u] + 1 && w) {
      int f = DFS(v, min(maxflow - ret, w), tt);
      e[i].w -= f;
      e[i ^ 1].w += f;
      ret += f;
      if (ret == maxflow)
        return ret;

    }
  }
  return ret;
}

int vis[MAX];

void Dinic() {
  int ans = 0;

  while (makediv() == 1) {
    memcpy(cur, head, sizeof(head));
    ans += DFS(ss, INF, tt);
  }

}
bool findd(int start,int end){
  memset(vis,0,sizeof(vis));
  queue<int> Q;
  Q.push(start);
  vis[start]=1;

  while(!Q.empty())
    {
      int u=Q.front();
      if(u==end)
        return true;
      Q.pop();
      for(int i=head[u];i!=-1;i=e[i].next)
        {
          int v=e[i].to;
          int w=e[i].w;
          if(w && !vis[v])
            {
              vis[v]=1;
              Q.push(v);
            }

        }
    }
  return false;
}

int main(void) {
    scanf("%d%d", &n, &m);
    int res=0;
    memset(head, -1, sizeof(head));
    cont = 0;
    ss=0;
    tt=n-1;
    int u,v,w;
    for(int i=1;i<=m;i++){
      scanf("%d%d%d",&u,&v,&w);
      add(u,v,w);
      add(v,u,0);
    }
    Dinic();
    for(int i=0;i<cont;i+=2){
      if( e[i].w!=0)
        continue;
      if(findd(ss,e[i].from) && findd(e[i].to , tt))
        {
          res++;
        }
    }
    printf("%d\n",res);
  return 0;
}

转载于:https://www.cnblogs.com/tennant/p/8982229.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值