POJ 3204 最大流

题意:问加哪些边容量增大能够增加整体流量。
很显然,增加单个边容量改变全局容量,一遍最大流之后,这些边只有可能出现在满流的边内,而且是一条路中唯一的一条满流边。
题解: 大众解法,一遍最大流之后,整个图跑残了,记录那些满流的边,从起点开始深搜,只走非满流边,从终点开始搜,只走非满流边,如果某条满流边起始点被起点标记,且终止点被终点标记,那么这条满流边存在于有且仅有他自己的从起点到终点的非满流路线中。这条边为关键边,Num++;
我的做法:既然一遍最大流之后 ,整个图跑残了,如果将某些关键边进行添加流量操作,将会重新出现一条从起点到终点的通路,我们可以直接在残余网络中加流,然后进行从起点到终点的广搜,如果可以到达   num ++,思路简单,但是由于多次广搜,如果用普通队列实现dinic会超时,虽然用数组模拟队列很不好,但是表示这样确实很省时间。
代码:
#include<stdio.h>
#include<iostream>
#include<queue>
#define INF 1000000000
#define N 1005 
#define M 10005
using namespace std;
int tot, list[N], deep[N], n, m, q[2000005];
struct Node
{
   int date, value, next, from;       
}cun[2000005];
struct dian
{
   int x, t;       
}old,xin;
void add(int a, int b, int c)
{
   cun[++tot].value = c;
   cun[tot].date = b;
   cun[tot].next = list[a];
   cun[tot].from = a;
   list[a] = tot;
   
   cun[++tot].value = 0;
   cun[tot].date = a;
   cun[tot].next = list[b];
   cun[tot].from = b;
   list[b] = tot;     
}
int BFS(int s,int t)  
{  
    int i,x,v,tail=0,head=0;  
    memset(deep,255,sizeof(deep));  
    deep[s]=0;  
    q[tail++]=s;  
   
    while(head<tail)  
    {   
        x=q[head++];          
        for(i=list[x];i;i=cun[i].next)  
         {//printf("!\n");
            if(cun[i].value&&deep[v=cun[i].date]==-1)  
            {  
                deep[v]=deep[x]+1;  
                if(v==t)  
                    return 1;  
                q[tail++]=v;  
            }  
}
    }  
    return 0;  
}  
int mmin(int a,int b)
{
   if(a<b)  return a;
   else return b;    
}
int DFS(int s,int t,int min)
{
   if(s==t)   return   min;
   int neww=0;
   for(int k=list[s];k;k=cun[k].next)         
      {
         int c=cun[k].value;
         int date=cun[k].date;
         if(c==0||deep[date]!=deep[s]+1) continue;
         int m=DFS(date,t,mmin(c,min-neww));
         neww+=m;
         cun[k].value-=m;
         cun[k^1].value+=m;
         if(neww==min)  break;
         
                 
      }
   if(neww==0)    deep[s]=0;
   return neww;
}
int dinic(int s,int t,int n)
{
    int num=0;
    while(BFS(s,t))
    {
         num+=DFS(s,t,INF);        
    }    
    return num;
}
void bulid()
{
     int a, b, c;
     for(int i = 0; i < m; i++ )
     {
       scanf("%d %d %d",&a, &b, &c);
       add(a+1, b+1, c);        
     }                  
     int k = dinic(1, n, n+5);
     int num = 0;
     for(int i = 2; i <= tot; i += 2)
     {
       if(!cun[i].value) 
       {
        cun[i].value += 1;
        if(BFS(1, n))  num++;
        cun[i].value -= 1;
       }
          
     }  
     printf("%d\n",num);
}
int main()
{
   while(scanf("%d%d",&n, &m)!=EOF)
   {
     memset(list,0,sizeof(list));
     tot = 1;
     bulid();
     
   }    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值