Title Link: POJ 1149 PIGS
PIGS
Time Limit: 1000MS |
|
Memory Limit: 10000K |
Total Submissions: 16533 |
|
Accepted: 7403 |
Description Mirko works on a pig farm This consists of M locked pig-houses and Mirko can ' t unlock any pighouse because He doesn ' t have the keys. Customers come to the farm one after another. Each of them have keys to some pig-houses and wants to buy a certain number of pigs. all data concerning custome RS planning to visit the farm on this particular day is available to Mirko early in the morning so and he can make a Sal Es-plan in order to maximize the number of pigs sold. More precisely, the procedure is as following:the custom Er arrives, opens all pig-houses to which he have the key, Mirko sells a certain number of pigs from all the unlocked pig-h Ouses to him, and, if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses. an un Limited number of pigs can be placed in every pig-house. Write a program that would find the maximum number of P IGs that he can sell on the day. Input the first line of input contains integers m and N, 1 <= m <=, 1 <= N <=, number of Pighouse s and number of customers. Pig houses is numbered from 1 to M and customers is numbered from 1 to N. The next line contains M Integeres, for each pig-house initial number of pigs. The number of pigs in pig-house are greater or equal to 0 and less or equal to 1000. The next N lines contains records about the customers in the following form (record on the i-th customer is written in The (i+2)-th line): A K1 K2 ... Ka B It means that this customer have key to the pig-houses marked with the numbers K1, K2, ..., Ka (sorted nondecreasingly ) and that he wants to buy B pigs. Numbers A and B can be equal to 0. Output the first and only line of the output should contain the number of sold pigs. Sample Input 3 3
3 1
2 1 2 2
2 1 3 3
1 2 6 Sample Output 7 Source Croatia OI 2002 Final Exam-first Day |
Analysis:
The key in this subject is how to compose a picture, so that the template can be solved directly. In fact, most of the network flow problems as long as the diagram is basically simple. But the composition is a mental process.
The composition method is as follows:
(1) Set a source point S, a meeting point T,
(2) The customer as the intermediate node,
(3) S and the first customer of each pigsty are connected to the side, the capacity is the number of pigs in the pigsty at the beginning. If there is a heavy edge with a node, the capacity value is combined (because the flow from the source point is the number of pigs that can be supplied by all pigsty),
(4) Customer J immediately after the customer I open a pigsty, the edge <i, j> capacity for the INF, because if the customer J immediately after the customer I open a pigsty, then Mike will be possible according to Customer J's request to the other pig in the pigsty, so that customer J can buy as many pigs,
(5) Each customer and meeting point between the edge, the capacity of the side is the number of pigs that customers want to buy.
after the composition is complete, the maximum flow can be solved. Three different methods
(1) EK algorithm, the shortest augmented path algorithm (that is, the first with BFS to broaden the road, and then augmented, but each time to BFS, time complexity is not good.
The implementation is as follows:
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <vector
> Using namespace std;
#define MAXN 1010 #define INF 0x3f3f3f3f int ans, s, T, N;
int A[MAXN], PRE[MAXN];
int FLOW[MAXN][MAXN];
int CAP[MAXN][MAXN];
void EK () {queue<int> q;
memset (flow, 0, sizeof (flow));
Ans = 0;
while (1) {memset (A, 0, sizeof (a));
A[s] = INF;
Q.push (s);
while (!q.empty ())//bfs find the augmented path {int u = q.front ();
Q.pop ();
for (int v = 1; v <= N; v++) if (!a[v] && cap[u][v] > Flow[u][v]) {
PRE[V] = u;
Q.push (v);
A[v] = min (A[u], cap[u][v]-flow[u][v]);
}} if (a[t] = = 0) break;
for (int u = t; u! = s; u = Pre[u])//Improved network stream {Flow[pre[u]][u] + = a[t];
Flow[u][pre[u]]-= a[t];
} Ans + = a[t];
}} int main () {//freopen ("Poj_1149.txt", "R", stdin);
int m, x, A, B, PIG[MAXN], PRE[MAXN];
memset (Cap, 0, sizeof (CAP));
scanf ("%d%d", &m, &n);
memset (Pre,-1, sizeof (pre)); s = 0;
t = n+1;
for (int i = 1; I <= m; i++) scanf ("%d", &pig[i]);
for (int i = 1; I <= n; i++) {scanf ("%d", &a);
for (int j = 0; J < A; J + +) {scanf ("%d", &x);
if (pre[x] = =-1) cap[s][i] + = pig[x];
else cap[pre[x]][i] = INF;
PRE[X] = i;
} scanf ("%d", &cap[i][t]);
} n + = 2;
EK ();
printf ("%d\n", ans);
return 0;
}
(2) Dinic algorithm. The same as the EK SAP algorithm, the use of a hierarchical graph to find the shortest, and then using DFS augmentation.
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <vector
> Using namespace std;
#define MAXN 1010 #define INF 0x3f3f3f3f struct Edge {int from, to, Cap;};
Vector<edge> EG;
Vector<int> G[MAXN];
int n, s, T, ans, D[MAXN], CUR[MAXN];
void Addedge (int from, int to, int caps) {Eg.push_back (Edge) {from, to, Cap});
Eg.push_back (Edge) {To, from, 0});
int x = Eg.size ();
G[from].push_back (x-2);
G[to].push_back (x-1);
} bool BFs () {memset (d,-1, sizeof (d));
Queue<int> Q;
Q.push (s);
D[s] = 0;
while (!q.empty ()) {int x = Q.front ();
Q.pop ();
for (int i = 0; i < g[x].size (); i++) {edge& e = eg[g[x][i]];
if (d[e.to] = =-1 && e.cap > 0) {d[e.to] = d[x]+1;
Q.push (e.to);
}}} return (D[t]!=-1); } int dfs (int x, int a) {IF (x = = T | | a = = 0) return A;
int flow = 0, F;
for (int& i = cur[x]; i < g[x].size (); i++) {edge& e = eg[g[x][i]];
if (d[x]+1 = = D[e.to] && (f = dfs (e.to, Min (A, e.cap))) > 0) {e.cap-= f;
Eg[g[x][i]^1].cap + = f;
Flow + + F;
A-= f;
if (a = = 0) break;
}} return flow;
} void Dinic () {ans = 0;
while (BFS ()) {memset (cur, 0, sizeof (cur));
Ans + = DFS (s, INF);
}} int main () {//freopen ("Poj_1149.txt", "R", stdin);
int m, x, A, B, PIG[MAXN], PRE[MAXN];
scanf ("%d%d", &m, &n);
memset (Pre,-1, sizeof (pre)); s = 0;
t = n+1;
for (int i = 1; I <= m; i++) scanf ("%d", &pig[i]);
for (int i = 1; I <= n; i++) {scanf ("%d", &a);
for (int j = 0; J < A; J + +) {scanf ("%d", &x);
if (pre[x] = =-1) Addedge (s, I, pig[x]); else Addedge (Pre[x], I, INF);
PRE[X] = i;
} scanf ("%d", &b);
Addedge (i, T, B);
} n + = 2;
Dinic ();
printf ("%d\n", ans);
return 0;
}
(3) ISAP, improved ISAP algorithm, is the best algorithm at present. It is also the shortest path through the hierarchical network, but the reverse bfs, and the BFS only needs to run once
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <vector
> Using namespace std;
#define MAXN 1010 #define INF 0x3f3f3f3f struct Edge {int from, to, cap, flow;};
Vector<edge> EG;
Vector<int> G[MAXN];
int n, s, T, ans, D[MAXN], CUR[MAXN], P[MAXN], NUM[MAXN];
BOOL VIS[MAXN];
void Addedge (int from, int to, int caps) {Eg.push_back (Edge) {from, to, Cap, 0});
Eg.push_back (Edge) {To, from, 0, 0});
int x = Eg.size ();
G[from].push_back (x-2);
G[to].push_back (x-1);
} void BFs () {memset (Vis, false, sizeof (VIS));
Queue<int> Q;
Vis[t] = true;
D[t] = 0;
Q.push (t);
while (!q.empty ()) {int x = Q.front ();
Q.pop ();
for (int i = 0; i < g[x].size (); i++) {edge& e = eg[g[x][i]^1];
if (!vis[e.from] && e.cap > E.flow) {vis[e.from] = true;
D[e.from] = d[x]+1; Q.pusH (E.from);
}}}} int augment () {int x = t, a = INF;
while (x! = s) {edge& E = eg[p[x]];
A = min (A, e.cap-e.flow);
x = Eg[p[x]].from;
} x = t;
while (x! = s) {Eg[p[x]].flow + = A;
Eg[p[x]^1].flow-= A;
x = Eg[p[x]].from;
} return A;
} void Isap () {ans = 0;
BFS ();
memset (num, 0, sizeof (num));
for (int i = 0; i < n; i++) num[d[i]]++;
int x = s;
memset (cur, 0, sizeof (cur));
while (D[s] < n) {if (x = = T) {ans + = augment ();
x = S;
} bool flag = FALSE;
for (int i = cur[x]; i < g[x].size (); i++) {edge& e = eg[g[x][i]];
if (E.cap > E.flow && d[x] = = d[e.to]+1) {flag = true;
P[e.to] = G[x][i];
CUR[X] = i;
x = e.to;
Break
}} if (!flag) { int m = n-1;
for (int i = 0; i < g[x].size (); i++) {edge& e = eg[g[x][i]];
if (E.cap > E.flow) m = min (M, d[e.to]);
} if (--num[d[x]] = = 0) break;
NUM[D[X] = m+1]++;
Cur[x] = 0;
if (x! = s) x = Eg[p[x]].from;
}}} void Clear () {eg.clear ();
for (int i = 0; i < n; ++i) g[i].clear ();
} int main () {//freopen ("Poj_1149.txt", "R", stdin);
int m, x, A, B, PIG[MAXN], PRE[MAXN];
scanf ("%d%d", &m, &n);
memset (Pre,-1, sizeof (pre)); s = 0;
t = n+1;
for (int i = 1; I <= m; i++) scanf ("%d", &pig[i]);
for (int i = 1; I <= n; i++) {scanf ("%d", &a);
for (int j = 0; J < A; J + +) {scanf ("%d", &x);
if (pre[x] = =-1) Addedge (s, I, pig[x]); else Addedge (Pre[x], I, INF);
PRE[X] = i;
} scanf ("%d", &b);
Addedge (i, T, B);
} n + = 2;
ISAP ();
printf ("%d\n", ans);
Clear ();
return 0;
}
Comparison