问题描述:找从源点s到汇点t能流过的最大流量
最大流问题
Ednonds-Karp
每次增广的时候用BFS,这样不用找所有可能增加的流量,减少了循环次数。
复杂度 O(VE^2) 适用于几百的数据,可以直接用邻接矩阵存储,要存反向边
注意两个顶点间可能有多条边,相加即可,这也是邻接矩阵的好处
cap[][]表示初始的容量
flow[][]表示当前增广的流量
q是BFS的队列啦 orz...
注意队列的操作,多组数据每次队列要清空的话只要在EK()过程中重新申明就好了
读入的时候好坑啊,要么 while(scanf("%d%d", &m, &n)!=EOF) 要么 while (cin>>m>>n)
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
#define MAXN 210
#define INF 0x7fffffff
int ansf,n,m,x,y,z;
int cap[MAXN][MAXN],flow[MAXN][MAXN],pre[MAXN],dis[MAXN];
void add(int x,int y,int z)
{
cap[x][y]+=z;
}
int EK(int s,int t)
{
queue<int> q;
memset(flow,0,sizeof(flow));
ansf=0;
for (;;) //新技能get啦~ 要不断从源点到汇点
{
memset(dis,0,sizeof(dis));//存从s走过来可以流经的最大流量
dis[s]=INF;
q.push(s);
while (!q.empty())
{
int u=q.front();q.pop();
for (int v=1;v<=n;v++)//邻接矩阵
if (!dis[v] && cap[u][v]>flow[u][v])//dis[v]==0表示没有访问过,注意这里不是>=,如果是>=,尽管dis变成0,也会不停地向queue中加节点,死循环=w=
{
pre[v]=u;//修改流的时候要往前走
q.push(v);
dis[v]=min(dis[u],cap[u][v]-flow[u][v]);
}
}
if (dis[t]==0) break;
//更新流量
for (int v=t;v!=s;v=pre[v])
{
flow[pre[v]][v]+=dis[t];
flow[v][pre[v]]-=dis[t];//反向边使得可以流回去
}
ansf+=dis[t];
}
return ansf;
}
int main()
{
while (scanf("%d%d", &m, &n)!=EOF)
{
memset(cap,0,sizeof(cap));
for (int i=1;i<=m;i++)
{
scanf("%d%d%d", &x, &y, &z);
add(x,y,z);
}
//Edmonds-Karp
printf("%d\n", EK(1,n));
}
return 0;
}
无向图的连通度:
指在图中删去最少的边或点,使得图中指定的两个点s和t,不连通
这个最小的数就是无向图的连通度
无向图的连通度分为点连通度和边连通度
poj1966
题意:给一张无向图,求点连通度
n=50
n^2枚举s和t
【我就直接贴过来啦~
- 【1】有向图的边连通度:
- 这个其实就是最小割问题。以s为源点,t为汇点建立网络,原图中的每条边在网络中仍存在,容量为1,
- 求该网络的最小割(也就是最大流)的值即为原图的边连通度。
- 【2】有向图的点连通度:
- 需要拆点。建立一个网络,原图中的每个点i在网络中拆成i'与i'',有一条边<i', i''>,容量为1
- (<s', s''>和<t', t''>例外,容量为正无穷)。原图中的每条边<i, j>在网络中为边<i'', j'>,
- 容量为正无穷。以s'为源点、t''为汇点求最大流,最大流的值即为原图的点连通度。
- 说明:最大流对应的是最小割。显然,容量为正无穷的边不可能通过最小割,也就是原图中的边和s、t两个点
- 不能删去;若边<i, i''>通过最小割,则表示将原图中的点i删去。
- 【3】无向图的边连通度:
- 将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【1】)处理;
- 【4】无向图的点连通度:
- 将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【2】)处理。
将边拆开是为了用网络流,拆完的边是有向边