poj 3281 Dining 拆点网络流
题目链接:http://poj.org/problem?id=3281
题意:
有N头牛,F种食物和D种饮料。
给出每头牛喜欢的一些食物和饮料。
每种饮料只能被分配给一只牛;每种食物也只能被分配给一只牛。
求能同时分配到食物和饮料的牛的最大数量。
思路:
设立一个超级源点和超级汇点。
超级源点向每个饮料连一条边,容量为1,代表每个饮料只能被分配一次。
每个食物向超级汇点连一条边,容量为1,代表每个食物只能被分配一次。
把每头牛拆分为2个点i和i',i向i’连边,容量为1。
把饮料和喜欢它的牛i连边,容量为1。
把牛i'向每个它喜欢的食物连边,容量为1。
最后求最大流。
拆点适用于一个点需要使用多次的情况以及有限制结点容量的情况。
对于一个点需要使用多次的情况,一般情况下,拆分后连一条边,容量为1。
对于限制结点容量的情况,把原始结点u分裂成u1和u2两个结点,中间连接一条有向弧,容量 = u的结点容量。
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <vector> 6 #include <queue> 7 using namespace std; 8 int n, m, s, t; 9 #define maxn 410 10 #define inf 0x3f3f3f3f 11 struct Edge 12 { 13 int from, to, cap, flow; 14 Edge(int f, int t, int c, int fl) 15 { 16 from = f; to = t; cap = c; flow = fl; 17 } 18 }; 19 vector <Edge> edges; 20 vector <int> G[maxn]; 21 int d[maxn], vis[maxn], cur[maxn]; 22 void AddEdge(int from, int to, int cap) 23 { 24 edges.push_back(Edge(from, to, cap, 0)); 25 edges.push_back(Edge(to, from, 0, 0)); 26 m = edges.size(); 27 G[from].push_back(m-2); 28 G[to].push_back(m-1); 29 } 30 bool bfs() 31 { 32 memset(vis, 0, sizeof(vis)); 33 d[s] = 0; 34 vis[s] = 1; 35 queue <int> q; 36 q.push(s); 37 while(!q.empty()) 38 { 39 int x = q.front(); q.pop(); 40 for(int i = 0; i < G[x].size(); i++) 41 { 42 Edge &e = edges[G[x][i]]; 43 if(!vis[e.to] && e.cap > e.flow) 44 { 45 d[e.to] = d[x] + 1; 46 vis[e.to] = 1; 47 q.push(e.to); 48 } 49 } 50 } 51 return vis[t]; 52 } 53 int dfs(int x, int a) 54 { 55 if(x == t || a == 0) return a; 56 int flow = 0, f; 57 for(int &i = cur[x]; i < G[x].size(); i++) 58 { 59 Edge &e = edges[G[x][i]]; 60 if(d[e.to] == d[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) 61 { 62 e.flow += f; 63 edges[G[x][i]^1].flow -= f; 64 flow += f; 65 a -= f; 66 if(a == 0) break; 67 } 68 } 69 return flow; 70 } 71 int maxflow() 72 { 73 int flow = 0; 74 while(bfs()) 75 { 76 memset(cur, 0, sizeof(cur)); 77 flow += dfs(s, inf); 78 } 79 return flow; 80 } 81 int N, F, D; 82 int main() 83 { 84 // freopen("in.txt", "r", stdin); 85 //freopen("out.txt", "w", stdout); 86 while(~scanf("%d%d%d", &N, &F, &D)) 87 { 88 edges.clear(); 89 for(int i = 0; i <= 2*N+F+D+1; i++) G[i].clear(); 90 s = 0; t = F+2*N+D+1; 91 n = F+2*N+D+2; 92 for(int i = 1; i <= F; i++) AddEdge(s, i, 1); 93 for(int i = 1; i <= D; i++) AddEdge(F+2*N+i, t, 1); 94 for(int i = 1; i <= N; i++) AddEdge(F+i, F+N+i, 1); 95 for(int i = 1; i <= N; i++) 96 { 97 int f, d; scanf("%d%d", &f, &d); 98 int temp; 99 while(f--) 100 { 101 scanf("%d", &temp); 102 AddEdge(temp, F+i, 1); 103 } 104 while(d--) 105 { 106 scanf("%d", &temp); 107 AddEdge(F+N+i, F+2*N+temp, 1); 108 } 109 } 110 int flow = maxflow(); 111 printf("%d\n", flow); 112 } 113 return 0; 114 }