昨天刚学的dinic算法,在这里记录一下
dinic算法与普通方法求最大流的思路类似,都是不断地寻找增广路并不断更新。而dinic算法新加入了一个设置分层图的方法,通过分层避免了增广路径因为反向边的添加,dfs时的盲目性导致增广效率低下的问题。而分层只需要设一个depth数组,然后每次bfs一下就好了。当bfs之后终点的深度不存才时,即不存在分层图,则增广路寻找完毕。(优化一)
然后就是从一个点找到一条增广路之后,可以继续从这个点开始找下一条增广路。这就避免了找到一条路之后,要找下一条就必须从头开始的情况了。(优化二)
再者,一次bfs之后可以进行多次dfs寻找增广路,没必要一次bfs一次dfs。(优化三)
此外,dinic算法还可以有一个优化。就是通过邻接表存图的时候,可以再开一个cur数组存放当前点增广到哪条边。这样dfs时就不用都从i = head[u]开始找,节省了一定的时间。不过要注意每次分层之后,因为分层变了,所以要将cur都初始化为第一条边即head。
题:洛谷 P2763 试题库问题
#include
#include
#include
using namespace std;
#define mem(a, i) memset(a, i, sizeof a)
const int maxn = 30030;
const int inf = 0x3f3f3f3f;
class Dinic
{
private:
int ans, cnt;
int n, s, t;
int type, maxk;
int head[maxn], next[maxn];
int W[maxn], V[maxn];
int depth[maxn], cur[maxn];
void init(int kk, int nn);
void add(int u, int v, int w);
bool bfs();
int dfs(int u, int dist);
void dinic();
void show();
public:
Dinic(int kk, int nn);
~Dinic();
};
Dinic::Dinic(int kk, int nn) : n(kk + nn + 2), t(kk + nn + 1), type(kk)
{
s = 0;
ans = 0;
cnt = -1;
maxk = 0;
mem(head, 0xff);
mem(next, 0xff);
init(kk, nn);
dinic();
}
Dinic::~Dinic()
{
Dinic::show();
}
void Dinic::add(int u, int v, int w)
{
cnt ++;
W[cnt] = w;
V[cnt] = v;
next[cnt] = head[u];
head[u] = cnt ++;
W[cnt] = 0;
V[cnt] = u;
next[cnt] = head[v];
head[v] = cnt;
}
void Dinic::init(int kk, int nn)
{
int x;
for(int i = 1; i <= kk; ++ i)
{
cin >> x;
maxk += x;
add(0, i, x);
}
int p;
for(int i = 1; i <= nn; ++ i)
{
add(kk + i, t, 1);
cin >> p;
for(int j = 1; j <= p; ++ j)
{
cin >> x;
add(x, kk + i, 1);
}
}
}
bool Dinic::bfs()
{
mem(depth, 0);
depth[s] = 1;
queue q;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = head[u]; ~i; i = next[i])
{
if(W[i] && !depth[V[i]])
{
depth[V[i]] = depth[u] + 1;
if(V[i] == t)
{
return true;
}
q.push(V[i]);
}
}
}
return false;
}
int Dinic::dfs(int u, int dist)
{
if(u == t)
{
return dist;
}
int tmp = 0;
for(int& i = cur[u]; ~i; i = next[i])
{
if(W[i] && depth[V[i]] == depth[u] + 1)
{
int di = dfs(V[i], min(W[i], dist));
if(di)
{
W[i] -= di;
W[i ^ 1] += di;
tmp += di; //优化二
dist -= di;
if(dist <= 0)
{
break;
}
}
}
}
return tmp;
}
void Dinic::dinic()
{
while(bfs()) //优化一
{
for(int i = 0; i <= t; ++ i)
{
cur[i] = head[i];
}
while(int di = dfs(s, inf)) //优化三
{
ans += di;
}
}
}
void Dinic::show()
{
if(ans == maxk)
{
for(int i = 1; i <= type; ++ i)
{
cout << i << ':';
for(int j = head[i]; ~j; j = next[j])
{
if(!W[j] && V[j] > type)
{
cout << ' ' << V[j] - type;
}
}
cout << endl;
}
}
else
{
cout << "No Solution!\n";
}
}
int main()
{
int k, n;
cin >> k >> n;
Dinic(k, n);
return 0;
}