插头Uva753——最大流

题意:

n个插座和m个插头,k种转换器(每种都是无限个,可以把插头转换成其他类型的插头),求最少剩多少个插头没插上插座。

思路:

首先给所有插头或插座以及转换器中涉及到的类型编号。然后根据转换器建立类型之间的转化关系,接着用Floyd算法算出每个设备所有适配的类型,并将其容量设为INF,表示转换器数量充足,可以有多个设备用同一种转换器。
接着构建网络:所有的设备类型和源点连一条弧,容量为1(注意累加,比如有2个设备类型都是B,那么从源点到B的容量应该为2),所有的插座类型和汇点连弧,容量为1。
然后用最大流算法

#include <iostream>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 400+5;
int n;
int Cap[maxn][maxn], flow[maxn][maxn], dis[maxn];

map<string, int> mp;
int ID(string s){
	int m = mp.size();
	if(mp.count(s) == 0) mp.insert(make_pair(s,m)); 
	return mp[s];
} 

void Floyd(){
	for(int k = 0; k < n; ++k){
		for(int i = 0; i < n; ++i){
			for(int j = 0; j < n; ++j){
				Cap[i][j] = Cap[i][j]||(Cap[i][k]&&Cap[k][j]);
				if(Cap[i][j]) Cap[i][j] = INF;
			}
		}
	}
}

bool bfs(int s, int t){
	memset(dis, -1, sizeof(dis));
	queue<int> Q;
	Q.push(s);
	dis[s] = 0;
	while(!Q.empty()){
		int x = Q.front(); Q.pop();
		for(int i = 0; i < n+2; ++i){
			if(dis[i] == -1&&Cap[x][i] > flow[x][i]){
				dis[i] = dis[x] + 1;
				Q.push(i);
			}
		}
	}
	return dis[t] != -1;
}

int dfs(int s, int t, int f){
	if(s == t||f == 0) return f;
	int ans = 0;
	for(int i = 0; i < n+2; ++i){
		if(dis[i] == dis[s] + 1&&Cap[s][i] > flow[s][i]){
			int a1 = min(f, Cap[s][i] - flow[s][i]);
			int a2 = dfs(i, t, a1);
			if(a2 == 0) continue;
			flow[s][i] += a2;
			flow[i][s] -= a2;
			ans += a2;
			f -= a2;
			if(f <= 0) break;
		}
	}
	return ans;
}

int dinic(int s, int t){
	int ans = 0;
	while(bfs(s, t)){
		//printf("hh");
		ans += dfs(s, t, INF);
	}
	return ans;
}


int main()
{
	//freopen("in.txt","r",stdin);
	int T,m,k; cin>>T;
	while(T--){
		memset(flow, 0, sizeof(flow));
		memset(Cap, 0, sizeof(Cap));
		mp.clear();
		string s, s2;
		vector<int> vec1, vec2;
		
		cin>>n;
		for(int i = 0; i < n; ++i) { cin>>s; vec1.push_back(ID(s));}
		cin>>m;
		for(int i = 0; i < m; ++i){ cin>>s>>s2; vec2.push_back(ID(s2));}
		cin>>k;
		for(int i = 0; i < k; ++i){
			cin>>s>>s2;
			Cap[ID(s)][ID(s2)] = INF;
		}
		
		n = mp.size();
		for(int i = 0; i < n; ++i) Cap[i][i] = INF;
		Floyd();
		
		for(int i = 0; i < vec2.size(); ++i) Cap[n][vec2[i]] += 1; // 超级源点 
		for(int i = 0; i < vec1.size(); ++i) Cap[vec1[i]][n+1] = 1; // 超级汇点
		int ans = dinic(n, n+1);
		cout<<m-ans<<endl;
		if(T) cout<<endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值