POJ 3498 March of the Penguins(网络最大流)

Description

Somewhere near the south pole, a number of penguins are standing on a number of ice floes. Being social animals, the penguins would like to get together, all on the same floe. The penguins do not want to get wet, so they have use their limited jump distance to get together by jumping from piece to piece. However, temperatures have been high lately, and the floes are showing cracks, and they get damaged further by the force needed to jump to another floe. Fortunately the penguins are real experts on cracking ice floes, and know exactly how many times a penguin can jump off each floe before it disintegrates and disappears. Landing on an ice floe does not damage it. You have to help the penguins find all floes where they can meet.

A sample layout of ice floes with 3 penguins on them.

Input

On the first line one positive number: the number of testcases, at most 100. After that per testcase:

  • One line with the integer N (1 ≤ N ≤ 100) and a floating-point number D (0 ≤ D  100 000 ), denoting the number of ice pieces and the maximum distance a penguin can jump.

  • N lines, each line containing xi, yi, ni and mi, denoting for each ice piece its X and Y coordinate, the number of penguins on it and the maximum number of times a penguin can jump off this piece before it disappears ( −10 000  xi, yi  10 000 , 0 ≤ ni ≤ 10, 1 ≤ mi ≤ 200).

Output

Per testcase:

  • One line containing a space-separated list of 0-based indices of the pieces on which all penguins can meet. If no such piece exists, output a line with the single number −1.

 

题目大意:有n块浮冰,每块冰上有ni只企鹅,他们最多能跳距离D,现在这些企鹅想在同一块冰上集中,但是呢,冰有裂缝,每块冰只能被企鹅在上面跳走mi次(跳进来和站在上面都不影响),问企鹅们可以集中在哪些浮冰上。

思路:拆点,每个点x拆成x和x',每个x到x'连边,容量为能跳多少次。然后如果i到j的距离不大于D,那么在i'到j连一条边,容量为无穷大。源点S到每一个点x连一条边,容量为有多少只企鹅在x上。最后,枚举每一个点x,x到汇点T连一条边,容量为无穷大,判断最大流是否等于企鹅的数量。

算法正确性说明:如此建图,每只企鹅都从源点开始走到汇点,但每个冰块只能经过cap[x->x']次,保证了企鹅只能从x跳走mi次。

PS:我枚举的时候,只是把前一条边的容量搞成0(要删掉好像好麻烦的样子),再新建一条从枚举点到汇点的边,这样就不用每次都建图了。

PS2:D居然是浮点数……还好没因此WA……

 

BFS+ISAP(235MS):

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 #include <algorithm>
  5 #include <cmath>
  6 using namespace std;
  7 
  8 const int MAXN = 222;
  9 const int MAXE = MAXN * MAXN * 2;
 10 const int INF = 0x3f3f3f3f;
 11 
 12 struct SAP {
 13     int head[MAXN], dis[MAXN], gap[MAXN], pre[MAXN], cur[MAXN];
 14     int to[MAXE], next[MAXE], flow[MAXE], cap[MAXE];
 15     int st, ed, n, ecnt;
 16 
 17     void init() {
 18         memset(head, 0, sizeof(head));
 19         ecnt = 2;
 20     }
 21 
 22     void add_edge(int u, int v, int f) {
 23         to[ecnt] = v; cap[ecnt] = f; flow[ecnt] = 0; next[ecnt] = head[u]; head[u] = ecnt++;
 24         to[ecnt] = u; cap[ecnt] = 0; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++;
 25         //printf("%d->%d cap=%d\n", u, v, f);
 26     }
 27 
 28     void bfs() {
 29         memset(dis, 0x3f, sizeof(dis));
 30         queue<int> que; que.push(ed);
 31         dis[ed] = 0;
 32         while(!que.empty()) {
 33             int u = que.front(); que.pop();
 34             ++gap[dis[u]];
 35             for(int p = head[u]; p; p = next[p]) {
 36                 int v = to[p];
 37                 if(dis[v] > n && cap[p ^ 1]) {
 38                     dis[v] = dis[u] + 1;
 39                     que.push(v);
 40                 }
 41             }
 42         }
 43     }
 44 
 45     int Maxflow(int ss, int tt, int nn) {
 46         st = ss, ed = tt, n = nn;
 47         int ans = 0, minFlow = INF, u;
 48         for(int i = 0; i <= n; ++i) {
 49             cur[i] = head[i];
 50             gap[i] = 0;
 51         }
 52         u = pre[st] = st;
 53         bfs();
 54         while(dis[st] < n) {
 55             bool flag = false;
 56             for(int &p = cur[u]; p; p = next[p]) {
 57                 int v = to[p];
 58                 if(cap[p] > flow[p] && dis[u] == dis[v] + 1) {
 59                     flag = true;
 60                     minFlow = min(minFlow, cap[p] - flow[p]);
 61                     pre[v] = u;
 62                     u = v;
 63                     if(u == ed) {
 64                         ans += minFlow;
 65                         while(u != st) {
 66                             u = pre[u];
 67                             flow[cur[u]] += minFlow;
 68                             flow[cur[u] ^ 1] -= minFlow;
 69                         }
 70                         minFlow = INF;
 71                     }
 72                     break;
 73                 }
 74             }
 75             if(flag) continue;
 76             int minDis = n - 1;
 77             for(int p = head[u]; p; p = next[p]) {
 78                 int v = to[p];
 79                 if(cap[p] > flow[p] && dis[v] < minDis) {
 80                     minDis = dis[v];
 81                     cur[u] = p;
 82                 }
 83             }
 84             if(--gap[dis[u]] == 0) break;
 85             gap[dis[u] = minDis + 1]++;
 86             u = pre[u];
 87         }
 88         return ans;
 89     }
 90 } G;
 91 
 92 struct Point {
 93     int x, y, n, m;
 94     void read() {
 95         scanf("%d%d%d%d", &x, &y, &n, &m);
 96     }
 97 };
 98 
 99 double dist(const Point &a, const Point &b) {
100     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
101 }
102 
103 int n, ss, tt;
104 int ans[110], cnt;
105 double d;
106 Point p[110];
107 
108 void make_graph() {
109     ss = 2 * n + 1, tt = ss + 1;
110     G.init();
111     for(int i = 1; i <= n; ++i)
112         if(p[i].n) G.add_edge(ss, 2 * i - 1, p[i].n);
113     for(int i = 1; i <= n; ++i) G.add_edge(2 * i - 1, 2 * i, p[i].m);
114     for(int i = 1; i <= n; ++i) {
115         for(int j = 1; j <= n; ++j) {
116             if(i == j || dist(p[i], p[j]) > d) continue;
117             G.add_edge(i * 2, j * 2 - 1, INF);
118         }
119     }
120 }
121 
122 int main() {
123     int T;
124     scanf("%d", &T);
125     while(T--) {
126         scanf("%d%lf", &n, &d);
127         for(int i = 1; i <= n; ++i) p[i].read();
128         int sum = 0;
129         for(int i = 1; i <= n; ++i) sum += p[i].n;
130         make_graph();
131         cnt = 0;
132         for(int i = 1; i <= n; ++i) {
133             G.add_edge(i * 2 - 1, tt, INF);
134             memset(G.flow, 0, sizeof(G.flow));
135             if(sum == G.Maxflow(ss, tt, tt)) ans[++cnt] = i - 1;
136             G.cap[G.ecnt - 2] = 0;
137         }
138         if(cnt == 0) puts("-1");
139         else {
140             for(int i = 1; i < cnt; ++i) printf("%d ", ans[i]);
141             printf("%d\n", ans[cnt]);
142         }
143     }
144 }
View Code

 

posted @ 2013-08-07 16:57  Oyking  阅读(411)  评论(0编辑  收藏  举报