网络流关键割的几种求法

方法1:

暴力的dfs

这里思路直观,但是效率低端。

方法2:
1.网络流一次后标记所有的节点为未定义状态
2.从残余网络中的s做一次bfs标记未定义节点为s集合
3.从t中做一次bfs标记所有未定义节点位t集合
4.枚举所有的满流且一个点在s集合一个点在t集合的边(网络流中的正向边),增加流量看是否可以从s到t

方法2求关键割
   
     
sap maxflow;
int roof, cnt, reach[V];

bool floodfill( int beg, int * reach, int clr)
{
queue
< int > q;
q.push(beg);
reach[beg]
= clr;
while ( ! q.empty())
{
beg
= q.front();
q.pop();
for (Edges * i = vfrom[beg]; i != NULL; i = i -> next)
{
if ( ! reach[i -> vto] && i -> ecap)
{
reach[i
-> vto] = clr;
q.push(i
-> vto);
}
}
}
return reach[roof];
}

int main()
{
// freopen("data.in", "r", stdin);
// freopen("file.out", "w", stdout);
int s, t, csc, n, m, vvfrom, vto, tmpcap;
scanf(
" %d " , & csc);
while (csc -- )
{
scanf(
" %d %d " , & n, & m);
s
= 0 , roof = t = n - 1 ;
maxflow.firststart();
for ( int i = 0 ; i < m; i ++ )
{
scanf(
" %d %d %d " , & vvfrom, & vto, & tmpcap);
maxflow.addedge(vvfrom, vto, tmpcap, i);
maxflow.addedge(vto, vvfrom,
0 , i);
}
maxflow.maxflowsap(n, s, t);
memset(reach,
0 , sizeof (reach));
floodfill(s, reach,
1 );
floodfill(t, reach,
2 );
cnt
= INF;
for ( int i = 0 ; i < n; i ++ )
{
for (Edges * j = vfrom[i]; j != NULL; j = j -> next)
{
if (reach[i] == 1 && reach[j -> vto] == 2 && ((j - pool) & 1 ) == 0 )
{
j
-> ecap ++ ;
int vst[V];
memset(vst,
0 , sizeof (vst));
if (floodfill(s, vst, 1 ))
cnt
= min(cnt, j -> id);
j
-> ecap -- ;
}

}
}


方法3:
1.网络流一次后标记所有的节点为未定义状态
2.从残留网络中的s做一次bfs标记为s集合
3.从残留网络中建立反图!!从t bfs一次标记所有节点位t集合(遇到的必定为未定义的)
4.枚举所有的且一个点在s集合一个点在t集合的边的满流的边(网络流中的正向边)就是关键割

//建立反图的过程可以省略,查看反响边是否有流量即可

方法3在编码量和效率上都是最优的

方法3求关键割
   
     
1 sap maxflow;
2   int cnt, reachs[V]
3
4   void floodfill( int beg, int * reach, Edges * vfrom[], int clr)
5 {
6 queue < int > q;
7 q.push(beg);
8 reach[beg] = clr;
9 while ( ! q.empty())
10 {
11 beg = q.front();
12 q.pop();
13 for (Edges * i = vfrom[beg]; i != NULL; i = i -> next)
14 {
15 if ( ! reach[i -> vto] && i -> ecap )
16 {
17 reach[i -> vto] = clr;
18 q.push(i -> vto);
19 }
20 }
21 }
22 }
23
24   int main()
25 {
26 // freopen("data.in", "r", stdin);
27 // freopen("file.out", "w", stdout);
28   int s, t, csc, n, m, vvfrom, vto, tmpcap;
29 scanf( " %d " , & csc);
30 while (csc -- )
31 {
32 scanf( " %d %d " , & n, & m);
33 s = 0 , t = n - 1 ;
34 maxflow.firststart();
35 for ( int i = 0 ; i < m; i ++ )
36 {
37 scanf( " %d %d %d " , & vvfrom, & vto, & tmpcap);
38 maxflow.addedge(vvfrom, vto, tmpcap, i);
39 maxflow.addedge(vto, vvfrom, 0 , i);
40 }
41 maxflow.maxflowsap(n, s, t);
42 firststart();
43 for (Edges * i = pool;i < topp;i ++ )
44 addedge(i -> vto,i -> vfrom,i -> ecap,i -> id);
45 memset(reachs, 0 , sizeof (reachs));
46 floodfill(s, reachs, vfrom, 1 );
47 floodfill(t, reacht, rg, 2 );
48 cnt = INF;
49 for (Edges * i = pool;i < topp;i += 2 )
50 {
51 if ( ! i -> ecap && reachs[i -> vfrom] == 1 && reacht[i -> vto] == 2 )
52 cnt = min(cnt,i -> id);
53 } // 求最小编号的关键割

你可能感兴趣的:(网络流)