题目大意:
就是现在有s个州, 每个州要么有工厂要么有原材料供应商或者什么都没有, 有的话只有一家
现在有t个运输公司分别提供运输服务
要求一个工厂只能匹配一个供应商,一个供应商只能供应一个工厂,且要满足一个运输公司只为其中一个匹配对服务(可以通过多个运输公司一起来传递来配对一个工厂和供应商)
问最大匹配对数
大致思路:
EC-final前最后一个题.....打完之后训练就结束了呢= =
表示这个题真是让我见识到了什么叫网络流不知道可不可以,先来一发T了再说...简直暴力出奇迹
可以考虑这么建图:
所有工厂和源点连一条容量为1的边, 然后供应商和汇点连一条容量为1的边
对于每一个运输公司,抽象出两个点p1, p2,连一条容量为1的边来控制公司只用一次
对于每一个该运输公司可以服务的点与p1连一条容量1的边, 与p2连一条容量1的边
于是跑一遍最大流就是答案了
这个图最坏情况下应该是1000*2+600+2个点
600*2*1000+1000+600条无向边(120W...)
然而网络流单组数据只跑了159ms.....好强大...
代码如下:
Result : Accepted Memory : 37712 KB Time : 156 ms
/* * Author: Gatevin * Created Time: 2015/12/11 0:11:10 * File Name: Yukinoshita_Yukino.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define maxn 2700 #define maxm 1202000 struct Edge { int u, v, nex, cap; Edge(){} Edge(int _u, int _v, int _nex, int _cap) { u = _u, v = _v, nex = _nex, cap = _cap; } }; Edge edge[maxm << 1]; int E; int head[maxn]; void add_Edge(int u, int v, int c) { edge[++E] = Edge(u, v, head[u], c); head[u] = E; edge[++E] = Edge(v, u, head[v], 0); head[v] = E; } int dep[maxn]; bool bfs(int start, int end) { int Q[maxn]; int l, r; l = r = 0; memset(dep, -1, sizeof(dep)); Q[r++] = start; dep[start] = 0; while(l != r) { int u = Q[l++]; if(l == maxn) l = 0; for(int i = head[u]; i + 1; i = edge[i].nex) { int v = edge[i].v; if(edge[i].cap > 0 && dep[v] == -1) { dep[v] = dep[u] + 1; Q[r++] = v; if(r >= maxn) r = 0; if(v == end) return 1; } } } return 0; } int dinic(int start, int end) { int res = 0; int top; int cur[maxn]; int stack[maxn]; while(bfs(start, end)) { memcpy(cur, head, sizeof(head)); int u = start; top = 0; while(1) { if(u == end) { int min = 1e9; int loc; for(int i = 0; i < top; i++) if(min > edge[stack[i]].cap) { min = edge[stack[i]].cap; loc = i; } for(int i = 0; i < top; i++) { edge[stack[i]].cap -= min; edge[stack[i] ^ 1].cap += min; } res += min; top = loc; u = edge[stack[top]].u; } for(int i = cur[u]; i + 1; cur[u] = i = edge[i].nex) if(edge[i].cap != 0 && dep[u] + 1 == dep[edge[i].v]) break; if(cur[u] != -1) { stack[top++] = cur[u]; u = edge[cur[u]].v; } else { if(top == 0) break; dep[u] = -1; u = edge[stack[--top]].u; } } } return res; } map<string, int> M; int main() { ios::sync_with_stdio(0); E = -1; memset(head, -1, sizeof(head)); int s, r, f, t; cin>>s>>r>>f>>t; string name; int S = 0, T = s + 2*t + 1; int cnt = 0; for(int i = 0; i < r; i++) { cin>>name; if(M.count(name) == 0) { M[name] = ++cnt; add_Edge(S, cnt, 1); } } for(int i = r + 1; i <= r + f; i++) { cin>>name; if(M.count(name) == 0) { M[name] = ++cnt; add_Edge(cnt, T, 1); } } for(int i = 1; i <= t; i++) { int x; cin>>x; int point1 = ++cnt, point2 = ++cnt; add_Edge(point1, point2, 1); while(x--) { cin>>name; if(M.count(name) == 0) M[name] = ++cnt; int num = M[name]; add_Edge(num, point1, 1); add_Edge(point2, num, 1); } } cout<<dinic(S, T)<<endl; return 0; }