POJ-3204 最大流+枚举

     题意是说给个有向图..起点与终点..问哪些边在容量增加后,从起点到终点的最大流会增加...

     首先跑出最大流..然后枚举剩余容量为0的边..若从图的起点到这条边的起点能走通..这条边得重点到图的终点能走通..则说明这条边增加容量..从起点到终点的最大流会增加..应该好理解吧~~感觉就是每次在做增广路时,只有一条边的剩余容量为当前增广路的最大流量...但由于做增广路时还可能在后面通过剩余网络来调整..可能会导致前面已经确定的边发生变化...因此这个过程就放在了做完了整个图起点到终点的最大流之后~


Program:

#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
#include<queue>
#define oo 2000000000
using namespace std;
struct node
{
      int x,y,c,next;
}line[50005];
int n,m,_link[605],ans,dis[605],way[605],num;
bool used[605];
queue<int> myqueue;
bool BFS()
{
      int i,h,k;
      while (!myqueue.empty()) myqueue.pop();
      memset(used,false,sizeof(used));
      memset(dis,0,sizeof(dis));
      myqueue.push(0);  used[0]=true;
      while (!myqueue.empty())
      {
            h=myqueue.front();
            myqueue.pop();
            k=_link[h]; 
            while (k)
            {
                  if (line[k].c && !used[line[k].y])
                  {
                          dis[line[k].y]=dis[h]+1;
                          used[line[k].y]=true;
                          myqueue.push(line[k].y); 
                  }
                  k=line[k].next;
            }
      }
      return used[n];
}
bool DFS(int p,int Flow)
{
      int k;
      if (p==n)
      {
            for (k=1;k<=num;k++)
            {
                   line[way[k]].c-=Flow;
                   m++;
                   line[m].x=line[way[k]].y;
                   line[m].y=line[way[k]].x;
                   line[m].c=Flow;
            }
            return true; 
      }
      num++;
      k=_link[p];
      while (k)
      {
            if (line[k].c && dis[line[k].y]-dis[line[k].x]==1)
            {
                   way[num]=k;
                   if (DFS(line[k].y,min(Flow,line[k].c))) return true;
            }
            k=line[k].next;
      }
      num--;
      return false;
}
void MaxFlow()
{ 
      if (!n) return;
      while (BFS()) 
      {
             num=0; 
             DFS(0,oo); 
      } 
      return;
}
bool ok(int s,int e)
{
      int h,k;
      while (!myqueue.empty()) myqueue.pop();
      memset(used,false,sizeof(used));
      myqueue.push(s);  used[s]=true;
      while (!myqueue.empty())
      {
             h=myqueue.front();
             myqueue.pop();
             k=_link[h];
             while (k)
             {
                   if (line[k].c && !used[line[k].y])
                   {
                         used[line[k].y]=true;
                         myqueue.push(line[k].y);
                   }
                   k=line[k].next;
             }
      }
      return used[e];
}
int main()
{
      int i;
      scanf("%d%d",&n,&m);
      memset(_link,0,sizeof(_link));
      for (i=1;i<=m;i++)
      {
            scanf("%d%d%d",&line[i].x,&line[i].y,&line[i].c);
            line[i].next=_link[line[i].x];
            _link[line[i].x]=i;
      }
      n--;
      MaxFlow();
      ans=0;
      for (i=1;i<=m;i++)
        if (!line[i].c && ok(0,line[i].x) && ok(line[i].y,n)) ans++; 
      printf("%d\n",ans);
      return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值