Flow Problem

Description

Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph.      
              

Input

The first line of input contains an integer T, denoting the number of test cases.       
For each test case, the first line contains two integers N and M, denoting the number of vertexes and edges in the graph. (2 <= N <= 15, 0 <= M <= 1000)       
Next M lines, each line contains three integers X, Y and C, there is an edge from X to Y and the capacity of it is C. (1 <= X, Y <= N, 1 <= C <= 1000)      
              

Output

For each test cases, you should output the maximum flow from source 1 to sink N.      
              

Sample Input

2 3 2 1 2 1 2 3 1 3 3 1 2 1 2 3 1 1 3 1
              

Sample Output

Case 1: 1 Case 2: 2

 

 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#define oo 1<<28
using namespace std;
int n,m,map[300][300];
int a[300],p[300],flow[300][300];
int start,end;
int Dinic()
{
    int u,v;
    queue<int>q;
    memset(flow,0,sizeof(flow));
    memset(p,0,sizeof(p));
    int f=0;
    while(1)
    {
        memset(a,0,sizeof(a));
        a[start]=oo;//oo是因为起点没有节点控制,先初始为最
        q.push(start);
        while(!q.empty())//bfs找增广路
        {
            int u=q.front();
            q.pop();
            for(v=1;v<=m;v++)
            {
                if(!a[v]&&map[u][v]>flow[u][v])//找到新节点,保证要流过的小于最大界限
                {
                    p[v]=u;
                    q.push(v);
                    a[v]=a[u]<map[u][v]-flow[u][v]?a[u]:map[u][v]-flow[u][v];//最小残量,保证此增光路上每一条都可通过,否则就成了死路
                }
            }
        }
        if(a[end]==0)
            break;
        for(u=end;u!=start;u=p[u])//从汇点向回流
        {
            flow[p[u]][u]+=a[end];//正向的加上此增广路上最小的值
            flow[u][p[u]]-=a[end];//同样反向的要减去
        }
        f+=a[end];
    }
    return f;
}
int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        memset(map,0,sizeof(map));
        memset(flow,0,sizeof(flow));
        int u,v,w;
        for(int i=0; i<n; i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            map[u][v]+=w; //防止有重边
        }
        start=1,  end=m;//开始于1,结束于m
        printf("%d\n",Dinic());
    }
    return 0;
}


 

<think>好的,我现在需要解决用户的问题:在最大流问题中,给定残余图Gr和当前流网络Gf的部分状态,如何确定原图G中边(v1, v2)或(v2, v1)的容量。用户可能正在学习最大流算法,比如Ford-Fulkerson或Edmonds-Karp,遇到了需要逆向推导原始容量的问题。这可能出现在作业题或考试题中,用户需要明确的分析步骤来找到答案。 首先,我得回忆最大流的基本概念。最大流问题中,残余图Gr的边表示在原图G中还能增加多少流量。残余容量分为正向边和反向边。正向边Gr中的容量是原边G中的容量减去已使用的流量,而反向边则是已使用的流量。因此,如果残余图中存在边(v1, v2)和(v2, v1),我需要结合当前流的状态来推断原始容量。 用户提到Gf是部分状态,可能是算法执行过程中的中间状态。根据Ford-Fulkerson方法,每次找到增广路径后更新残余图。因此,Gr的结构会随着流的改变而变化。为了确定原始容量,必须考虑当前流的值对残余容量的影响。 假设在残余图Gr中,边(v1, v2)有残余容量c1,而边(v2, v1)有残余容量c2。根据残余图的定义,原图G中的边可能有以下几种情况: 1. 原图G中存在边(v1, v2),其容量为C。此时,残余图中的正向边(v1, v2)的残余容量为C - f,其中f是当前流量。而反向边(v2, v1)的残余容量是f,因为反向边代表可以退回的流量。 2. 如果原图G中没有边(v1, v2),但存在反向边(v2, v1),则残余图中的正向边(v1, v2)可能来自于反向边的残余容量,即原边(v2, v1)的流量f,此时残余容量为f,而原边的容量C = f + 残余图中的反向边(v2, v1)的残余容量(如果有的话)。 用户的问题没有给出具体的残余图数值,所以可能需要一般性的推导方法。例如,如果在残余图中,边(v1, v2)的容量为a,边(v2, v1)的容量为b,那么原边(v1, v2)的原始容量C = a + (原边的反向流量,即残余图中的b)。不过需要明确当前流的情况,这可能涉及到联立方程。 可能的步骤包括: - 确定残余图中各边的残余容量。 - 根据残余容量的定义,建立方程。 - 解方程得到原始容量。 假设用户提供的残余图中,边(v1, v2)在Gr中的残余容量是r1,边(v2, v1)的残余容量是r2。那么原边(v1, v2)的原始容量C = r1 + r2,如果原图中有这条边的话。因为残余的正向容量是C - f,而反向残余容量是f,所以C = (C - f) + f = r1 + r2。这可能是一个关键点。 但需要注意,如果原图中原本没有边(v2, v1),那么残余图中的(v2, v1)边可能来自于其他边的反向,比如原边是(v1, v2),此时残余的反向边(v2, v1)的容量等于已使用的流量f,而正向残余容量是C - f。因此,在这种情况下,原容量C = r1 + r2,其中r1是残余正向边,r2是残余反向边。 用户可能需要这个推导过程,并且结合具体的例子来验证。例如,如果残余图中(v1, v2)有残余3,(v2, v1)有残余2,那么原边(v1, v2)的容量应该是3 + 2 = 5。这符合残余容量的定义:C = (C - f) + f = 残余正向 + 残余反向。 不过,还需要考虑原图中是否同时存在双向边的情况,即既有(v1, v2)又有(v2, v1),但通常在流网络中,原图可能不包含双向边,或者需要特殊处理。这种情况下,可能需要更多的信息来确定,但一般来说,题目中可能假设原图只有单向边,所以残余图中的反向边都是由于正向边的流量产生的。 综上,答案应该是原边的容量等于残余图中正向和反向残余容量之和,即C = r1 + r2,其中r1是Gr中(v1, v2)的残余容量,r2是Gr中(v2, v1)的残余容量。需要确认这一点是否正确,是否有例外情况,例如当原图中存在反向边时如何处理,但通常在标准问题中,原图只有单向边,因此上述结论成立。</think>#### 解答:确定原图G中边容量的方法 在最大流问题中,残差图$G_r$的边容量与原图$G$的边容量及当前流量存在直接数学关系。通过分析残差图中的边容量,可以逆向推导原始图的边容量。以下是具体推导过程: --- ### 一、核心公式推导 设原图$G$中边$(v_1, v_2)$的原始容量为$c_{12}$,当前流量为$f_{12}$。根据残差图的定义: 1. **残差正向边**$(v_1, v_2)$的容量为: $$ c_r^{\text{forward}} = c_{12} - f_{12} $$ 2. **残差反向边**$(v_2, v_1)$的容量为: $$ c_r^{\text{backward}} = f_{12} $$ 联立上述两式,可直接得到原边容量: $$ c_{12} = \underbrace{c_r^{\text{forward}}}_{\text{残差正向容量}} + \underbrace{c_r^{\text{backward}}}_{\text{残差反向容量}} $$ --- ### 二、具体案例分析 假设残差图$G_r$中观察到以下边容量: - $(v_1, v_2)$的残差容量为$3$ - $(v_2, v_1)$的残差容量为$2$ 则原图$G$中边$(v_1, v_2)$的原始容量为: $$ c_{12} = 3 + 2 = 5 $$ --- ### 三、特殊情况处理 1. **原图存在反向边**$(v_2, v_1)$的情况 若原图$G$中原本存在边$(v_2, v_1)$且容量为$c_{21}$,则需建立联立方程: $$ \begin{cases} c_{12} - f_{12} = c_r(v_1, v_2) \\ c_{21} + f_{12} = c_r(v_2, v_1) \end{cases} $$ 需额外信息(如总流量约束)才能解出$c_{12}$和$c_{21}$。 2. **原图无反向边** 若原图$G$中**仅存在单向边**$(v_1, v_2)$,则残差反向边$(v_2, v_1)$的容量完全由流量$f_{12}$决定,此时$c_{12} = c_r^{\text{forward}} + c_r^{\text{backward}}$**恒成立**[^2]。 --- ### 四、验证示例 **原始图$G$**: - 边$(A, B)$容量$5$,当前流量$2$ - 残差正向边$(A, B)$容量$3$,残差反向边$(B, A)$容量$2$ 验证公式: $$ c_{12} = 3 + 2 = 5 \quad \text{(与原始容量一致)} $$ --- ### 五、关键结论 | 残差图边类型 | 残差容量表达式 | 原始容量计算 | |--------------|----------------------|-----------------------| | $(v_1, v_2)$ | $c_r^{\text{forward}}$ | $c_{12} = c_r^{\text{forward}} + c_r^{\text{backward}}$ | | $(v_2, v_1)$ | $c_r^{\text{backward}}$ | (仅当原图无反向边时成立) | --- ### 六、算法实现参考 通过残差图直接读取边容量并计算: ```python def get_original_capacity(G_r, u, v): forward = G_r.get_edge_capacity(u, v) # 残差正向边容量 backward = G_r.get_edge_capacity(v, u) # 残差反向边容量 return forward + backward ``` 源码参考:[^3] --- #### 相关问题 1. 如何通过残差图判断当前流是否为最大流? 2. 残差图中反向边容量为0时意味着什么? 3. 如何处理原图中存在双向边的情况? [^1]: 最大流问题需通过残差图动态更新流量状态 [^2]: 残差图定义基于Ford-Fulkerson方法的核心思想 [^3]: 源码示例见GitHub仓库中的最小费用最大流实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值