1. 程式人生 > >網路流之最大流(Dinic演算法)

網路流之最大流(Dinic演算法)

程式碼對應於 POJ - 3281


#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

#define fuck cout << "wtf????\n"

using namespace std;

const int maxn = 300000;
const int inf = 0x3f3f3f3f;

class Dinic
{
private:
	int s, t;
	int cnt;
	int head[maxn], next[maxn];
	int V[maxn], W[maxn];
	int depth[maxn];
	int cur[maxn];
public:
	int n;
	void init(int nn, int ss, int tt)
	{
		n = nn;
		s = ss;
		t = tt;
		cnt = -1;
		memset(head, -1, sizeof head);
		memset(next, -1, sizeof next);
		return ;
	}
	void _Add(int u, int v, int w)
	{
		cnt ++;
		next[cnt] = head[u];
		V[cnt] = v;
		W[cnt] = w;
		head[u] = cnt;
	}
	void Add_Edge(int u, int v, int w)
	{
		_Add(u, v, w);
		_Add(v, u, 0);
	}
	int dfs(int u, int dist)
	{
		if(u == t)
		{
			return dist;
		}
		for(int i = head[u]; i != -1; i = next[i])
		{
			if(depth[V[i]] == depth[u] + 1 && W[i] != 0)
			{
				int di = dfs(V[i], min(dist, W[i]));
				if(di > 0)
				{
					W[i] -= di;
					W[i ^ 1] += di;
					return di;
				}
			}
		}
		return 0;
	}
	bool bfs()
	{
		queue <int> Q;
		memset(depth, 0, sizeof depth);
		depth[s] = 1;
		Q.push(s);
		while(!Q.empty())
		{
			int now = Q.front();
			Q.pop();
			for(int i = head[now]; i != -1; i = next[i])
			{
				if(W[i] > 0 && depth[V[i]] == 0)
				{
					depth[V[i]] = depth[now] + 1;
					Q.push(V[i]);
                    if(V[i] == t)
                    {
                        return true;
                    }

				}
				
            }
		}
		return false;
	}
	int dinic()
	{
		int ans = 0;
		while(bfs())
		{
			int d = dfs(s, inf);
			ans += d;
		}
		return ans;
	}
};

int main()
{
    //freopen("in.txt", "r", stdin);
	int N, F, D;
	cin >> N >> F >> D;
	Dinic C;
	int ss = 1, tt = 1 + F + 2 * N + D + 1;
	C.init(2 * N + F + D + 2, ss, tt);
	for(int i = 1; i <= F; ++ i)
	{
		C.Add_Edge(ss, ss + i, 1);    ///食物連線源點
	}
	for(int i = 1 + F + 2 * N + 1; i < tt; i ++)
	{
		C.Add_Edge(i, tt, 1);           ///飲料連線匯點
	}
	int fi, di, f, d;
	for(int i = 1; i <= N; ++ i)
	{
		C.Add_Edge(ss + F + i, ss + F + N + i, 1);
		cin >> fi >> di;
		while(fi --)
		{
			scanf("%d", &f);
			C.Add_Edge(ss + f, ss + F + i, 1);
		}
		while(di --)
		{
			scanf("%d", &d);
			C.Add_Edge(ss + F + N + i, ss + F + 2 * N + d, 1);
		}
	}
	cout << C.dinic() << endl;
	return 0;
}