POJ 3281:Dining(最大流)
http://poj.org/problem?id=3281
题意:有n头牛,f种食物,d种饮料,每头牛有fnum种喜欢的食物,dnum种喜欢的饮料,每种食物如果给一头牛吃了,那么另一个牛就不能吃这种食物了,饮料也同理,问最多有多少头牛可以吃到它喜欢的饮料和食物。
思路:一开始还以为二分匹配可以做,当然如果只有食物或者饮料其中一种就可以做。难点在于建图。看了下书,因为要保证经过牛的流量是1(每种食物对应分配给一头牛,每种饮料对应分配给一头牛,避免一头牛吃多份),所以要把牛拆成两个点。形成这样的路径S->f->cow1->cow2->d->T。
算法思想大概是通过BFS构造出分层图,然后通过DFS找增广路更新边流量和最大流的信息。
转的图。
2 #include <cstring> 3 #include <vector> 4 #include <queue> 5 using namespace std; 6 #define N 410 7 #define INF 0x3f3f3f3f 8 struct Edge { 9 int u, v, cap; 10 Edge () {} 11 Edge (int u, int v, int cap) : u(u), v(v), cap(cap) {} 12 }edge[N*N]; 13 vector<int> G[N]; 14 int tot, S, T, dis[N], cur[N]; 15 16 void AddEdge(int u, int v, int c) { 17 G[u].push_back(tot); 18 edge[tot++] = Edge(u, v, c); 19 G[v].push_back(tot); 20 edge[tot++] = Edge(v, u, 0); // 反向弧的流量是0 21 } 22 23 int BFS() { 24 queue<int> que; 25 que.push(S); 26 memset(dis, INF, sizeof(dis)); 27 dis[S] = 0; 28 while(!que.empty()) { 29 int u = que.front(); que.pop(); 30 for(int i = 0; i < G[u].size(); i++) { 31 Edge &e = edge[G[u][i]]; 32 if(e.cap > 0 && dis[e.v] == INF) { 33 dis[e.v] = dis[u] + 1; 34 que.push(e.v); 35 } 36 } 37 } 38 return dis[T] < INF; 39 } 40 41 int DFS(int u, int maxflow) { 42 if(u == T) return maxflow; 43 for(int i = cur[u]; i < G[u].size(); i++) { 44 cur[u] = i; 45 Edge &e = edge[G[u][i]]; 46 if(dis[e.v] == dis[u] + 1 && e.cap > 0) { 47 int flow = DFS(e.v, min(maxflow, e.cap)); 48 if(flow) { 49 e.cap -= flow; 50 edge[G[u][i]^1].cap += flow; 51 return flow; 52 } 53 } 54 } 55 return 0; 56 } 57 58 int Dinic() { 59 int ans = 0, flow; 60 while(BFS()) { 61 // puts("BFS"); 62 memset(cur, 0, sizeof(cur)); 63 while(flow = DFS(S, INF)) ans += flow; 64 } 65 return ans; 66 } 67 68 int main() { 69 int n, f, d; 70 while(~scanf("%d%d%d", &n, &f, &d)) { 71 S = 0, T = 2 * n + f + d + 1, tot = 0; 72 for(int i = 0; i <= T; i++) G[i].clear(); 73 for(int i = 1; i <= f; i++) 74 AddEdge(S, 2 * n + i, 1); // 源点到食物 75 for(int i = 1; i <= d; i++) 76 AddEdge(2 * n + f + i, T, 1); // 饮料到汇点 77 for(int i = 1; i <= n; i++) { 78 int fnum, dnum; 79 scanf("%d%d", &fnum, &dnum); 80 AddEdge(i, n + i, 1); // 每只牛拆点 81 for(int j = 1; j <= fnum; j++) { 82 int v; scanf("%d", &v); 83 AddEdge(2 * n + v, i, 1); // 食物到牛的第一个点 84 } 85 for(int j = 1; j <= dnum; j++) { 86 int v; scanf("%d", &v); 87 AddEdge(n + i, 2 * n + f + v, 1); // 牛的第二个点到饮料 88 } 89 } 90 int ans = Dinic(); 91 printf("%d\n", ans); 92 } 93 return 0; 94 }