1. 程式人生 > 實用技巧 >POJ1087-A Plug for UNIX(最大流)

POJ1087-A Plug for UNIX(最大流)

題意:買了n個插座,m個電器,k個轉換器。\(n(1 <= n <= 100)(1 <= m <= 100)(1 <= k <= 100)\),轉換器會把\(s1 s2\)中的s2插座轉換成s1插座。

//插座個數
4
A
B
C
D
//插頭個數
5
laptop B 
phone C 
pager B 
clock B 
comb X 
//轉換器種類
3 
B X 
X A 
X D

分析:我們可以用map為每個插座賦值一個id,我們從源點向插座連一條容量為1的邊,因為每個插座只能適配一個插頭。其次,我們為每個插頭也賦值一個id,從適配的插座向插頭連邊,容量為1。然後插頭再向匯點連邊。我們的交換器比如\(s1 s2\)

,表示s2的插座器可以向s1的插座器連邊,容量為inf。因為交換器是無限的。

注意:每次賦值都要判斷一個型別的插座或者插頭是否存在。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>

using namespace std;

const int inf = 1 << 29, N = 2005, M = 2 * N;
int h[N], e[M], ne[M], d[N];
int w[M];

int s, t, idx, maxflow;

void add(int a, int b, int c)
{
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
	e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}

//構造分層圖
bool bfs()
{
	memset(d, 0, sizeof d);
	queue<int> q;
	q.push(s), d[s] = 1;
	while (q.size())
	{
		int u = q.front();
		q.pop();
		for (int i = h[u]; i != -1; i = ne[i])
		{
			int j = e[i];
			if (w[i] && !d[j])
			{
				q.push(j);
				d[j] = d[u] + 1;
				if (j == t) return true;
			}
		}
	}
	return false;
}

int dinic(int u, int flow)
{
	if (u == t) return flow;
	int rest = flow, k;
	for (int i = h[u]; i != -1 && rest; i = ne[i])
	{
		int j = e[i];
		if (w[i] && d[j] == d[u] + 1)
		{
			k = dinic(j, min(rest, w[i]));
			if (!k) d[j] = 0;
			w[i] -= k;
			w[i ^ 1] += k;
			rest -= k;
		}
	}
	return flow - rest;
}

map<string, int> mp;

int main()
{	
	memset(h, -1, sizeof h);
	s = 0, t = 1000;
	//插座個數
	int n;
	scanf("%d", &n);
	string name, name2;

	int id = 0;
	for (int i = 1; i <= n; ++i)
	{
		cin >> name;
		mp[name] = ++id;
		//源點向插座連邊
		add(s, id, 1);
	}
	int m;
	//插頭個數
	scanf("%d", &m);

	for (int i = 1; i <= m; ++i)
	{
		//插頭名和插頭型別
		cin >> name >> name2;
		mp[name] = ++id;
		if (mp.find(name2) == mp.end())
		{
			mp[name2] = ++id;
		}
		//插座向插頭連邊
		add(mp[name2], mp[name], 1);
		//插頭向匯點連邊
		add(mp[name], t, 1);
	}

	int k;
	scanf("%d", &k);
	for (int i = 1; i <= k; ++i)
	{
		cin >> name >> name2;
		if (mp.find(name) == mp.end())
			mp[name] = ++id;
		if (mp.find(name2) == mp.end())
			mp[name2] = ++id;
		add(mp[name2], mp[name], inf);
	}

	int flow = 0;
	while (bfs())
	{
		while (flow = dinic(s, inf)) maxflow += flow;
	}

	printf("%d\n", m - maxflow);

	return 0;
}