A Plug for UNIX(网络流-最大流-dinic算法)

A Plug for UNIX(网络流-最大流-dinic算法)

judge:POJ 1087
Time Limit: 1000MS
Memory Limit: 65536K
source:East Central North America 1999

Description

You are in charge of setting up the press room for the inaugural meeting of the United Nations Internet eXecutive (UNIX), which has an international mandate to make the free
……
POJ 1087

Input

POJ 1087

Sample Input

4
A
B
C
D
5
laptop B
phone C
pager B
clock B
comb X
3
B X
X A
X D

Sample Output

1

题意

题意不太好理解,大概是这样:有一个房间,房间里有n种插座,每种插口都不同,且每种插座都只有一个。这时有m种电器,告诉了你每个电器对应的插座是哪种类型,并且还给了你一些转换器,A-B即插头A能插到插座B上。问你最少有几个电器木得插座插。即:插头数 - 最大匹配

建立超级源点和超级汇点,把插头连到源点上,把插座连到汇点上,再根据每种插头对应的插座连点:A Plug for UNIX(网络流-最大流-dinic算法)_第1张图片
再加入转换器:A Plug for UNIX(网络流-最大流-dinic算法)_第2张图片
注意,虽然转换器是无限的,但插座却是有限的,所以转换器也就相当于每种只有一个。
然后就开始愉快地连线啦( •̀ ω •́ )y
A Plug for UNIX(网络流-最大流-dinic算法)_第3张图片

代码

#include 
#include 
#include 
#include 
#include 
#include 
#define _for(i, a) for(int i = 0; i < (a); i++)
#define _rep(i, a, b) for(int i = (a); i <= (b); i++)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
using namespace std;

struct poi {
	int u, v, cap, next;//w 0 drinks	1 vegetable
}edges[maxn];

int head[maxn], cnt;
int n, m, k;
int dis[maxn];
int S, T;
int cur[maxn];
map<string, int> mp;
vector<int> num[maxn];

void init() {
	memset(head, -1, sizeof(head));
	memset(edges, 0, sizeof(edges));
	cnt = 0;
	memset(num, 0, sizeof(num));
}

void adde(int u, int v, int w) {
	edges[cnt].u = u, edges[cnt].v = v, edges[cnt].cap = w;
	edges[cnt].next = head[u], head[u] = cnt++;
	edges[cnt].u = v, edges[cnt].v = u, edges[cnt].cap = 0;
	edges[cnt].next = head[v], head[v] = cnt++;
}

//bfs 分层次
bool bfs() {
	memset(dis, 0, sizeof(dis));
	dis[S] = 1;
	queue<int> Q;
	Q.push(S);
	int flow = 0;
	while (!Q.empty()) {
		int u = Q.front();
		Q.pop();
		for (int i = head[u]; ~i; i = edges[i].next) {
			int v = edges[i].v, cap = edges[i].cap;
			if (cap > 0 && !dis[v]) {
				dis[v] = dis[u] + 1;
				Q.push(v);
			}
		}
	}
	return dis[T] != 0;
}

//dfs 找增广路
int dfs(int u, int mw) {
	if (u == T || mw == 0) return mw;
	int flow = 0;
	for (int &i = cur[u]; ~i; i = edges[i].next) {
		int v = edges[i].v, cap = edges[i].cap;
		if (cap > 0 && dis[v] == dis[u] + 1) {
			int cw = dfs(v, min(mw, cap));
			flow += cw;
			edges[i].cap -= cw;
			edges[i ^ 1].cap += cw;
			mw -= cw;
			if (mw == 0) break;
		}
	}
	return flow;
}

//主进程
int dinic() {
	int res = 0;
	while (bfs()) {
		memcpy(cur, head, sizeof(head));
		res += dfs(S, inf);
	}
	return res;
}

int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false);
	while (cin >> n) {
		init();
		string c;
		_rep(i, 1, n) {
			cin >> c;
			mp[c] = i;
		}
		cin >> m;
		_rep(i, n + 1, n + m) {
			cin >> c;
			cin >> c;
			if (!mp.count(c)) mp[c] = mp.size() + 1;
			num[i].push_back(mp[c]);
		}

		S = n + m + 1;
		T = S + 1;

		_rep(i, 1, n) adde(i, T, 1);

		cin >> k;
		_rep(i, 1, k) {
			string u, v;
			cin >> u >> v;
			adde(mp[u], mp[v], inf);
		}
		_rep(i, n + 1, n + m) {
			adde(S, i, 1);
			_for(j, num[i].size()) {
				adde(i, num[i][j], 1);
			}
		}
		cout << m - dinic() << "\n";
	}
	return 0;
}

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