hlg1512March of the Penguins【无向图+拆点】

 

March of the Penguins
Time Limit: 2000 MS Memory Limit: 65535 K
Total Submit: 14(7 users) Total Accepted: 9(6 users) Rating:  Special Judge: No
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.

 

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 ≤ 100000), 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.
Sample Input
2
5 3.5
1 1 1 1
2 3 0 1
3 5 1 1
5 1 1 1
5 4 0 1
3 1.1
-1 0 5 10
0 0 3 9
2 0 1 1

 

Sample Output
1 2 4
-1

 

Source
NWERC2007

 

大意:有n块冰块,每块冰块上有一定数量企鹅,并且有一定的跳跃次数(jump off)超过这个次数冰块就会碎掉

告诉每块冰块的企鹅数目和跳跃次数,问那些冰块能使所有的企鹅都到达(冰块编号从零开始)

 

模型:

1、首先这是一个无向图, 所以冰块之间建立路径的时候要件两条路

2、节点有权值(跳跃次数) 所以要拆点

 

思路:

冰块拆点之间的权值是跳跃次数

若两冰块之间能到达则建立两条路径(s1,t1)(s2,t2)的话  则由t1指向s2 由t2指向s1,权值为无穷

超级源点跟每块冰块的s建立一条路径,权值为企鹅数量

最后依次枚举每个点做汇点的最大流是否等于企鹅数量即可

 

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 #include <queue>
  6 #include <cmath>
  7 using namespace std;
  8 
  9 const int maxn = 505;
 10 const int INF = 10000000;
 11 
 12 struct Point{
 13     int x, y, ni, mi;
 14 }point[maxn];
 15 
 16 
 17 struct Edge
 18 {
 19     int from, to, cap, flow, flow2;
 20 };
 21 
 22 struct ISAP {
 23   int n, m, s, t;
 24   vector<Edge> edges;
 25   vector<int> G[maxn];
 26   bool vis[maxn];
 27   int d[maxn];
 28   int cur[maxn];
 29   int p[maxn];
 30   int num[maxn];
 31 
 32   void AddEdge(int from, int to, int cap) {
 33     edges.push_back((Edge){from, to, cap, 0, 0});
 34     edges.push_back((Edge){to, from, 0, 0, 0});
 35     m = edges.size();
 36     G[from].push_back(m-2);
 37     G[to].push_back(m-1);
 38   }
 39 
 40   void init() {
 41     for(int i = 0; i < m; i++){
 42         edges[i].flow = edges[i].flow2;
 43     }
 44   }
 45 
 46   bool BFS() {
 47     memset(vis, 0, sizeof(vis));
 48     queue<int> Q;
 49     Q.push(t);
 50     vis[t] = 1;
 51     d[t] = 0;
 52     while(!Q.empty()) {
 53       int x = Q.front(); Q.pop();
 54       for(int i = 0; i < G[x].size(); i++) {
 55         Edge& e = edges[G[x][i]^1];
 56         if(!vis[e.from] && e.cap > e.flow) {
 57           vis[e.from] = 1;
 58           d[e.from] = d[x] + 1;
 59           Q.push(e.from);
 60         }
 61       }
 62     }
 63     return vis[s];
 64   }
 65 
 66   void ClearAll(int n) {
 67     this->n = n;
 68     for(int i = 0; i < n; i++) G[i].clear();
 69     edges.clear();
 70   }
 71 
 72   int Augment() {
 73     int x = t, a = INF;
 74     while(x != s) {
 75       Edge& e = edges[p[x]];
 76       a = min(a, e.cap-e.flow);
 77       x = edges[p[x]].from;
 78     }
 79     x = t;
 80     while(x != s) {
 81       edges[p[x]].flow += a;
 82       edges[p[x]^1].flow -= a;
 83       x = edges[p[x]].from;
 84     }
 85     return a;
 86   }
 87 
 88   int MaxFlow(int s, int t, int need) {
 89     this->s = s; this->t = t;
 90     int flow = 0;
 91     BFS();
 92     memset(num, 0, sizeof(num));
 93     for(int i = 0; i < n; i++) num[d[i]]++;
 94     int x = s;
 95     memset(cur, 0, sizeof(cur));
 96     while(d[s] < n) {
 97       if(x == t) {
 98         flow += Augment();
 99         if(flow >= need) return flow;
100         x = s;
101       }
102       int ok = 0;
103       for(int i = cur[x]; i < G[x].size(); i++) {
104         Edge& e = edges[G[x][i]];
105         if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advance
106           ok = 1;
107           p[e.to] = G[x][i];
108           cur[x] = i;
109           x = e.to;
110           break;
111         }
112       }
113       if(!ok) {
114         int m = n-1;
115         for(int i = 0; i < G[x].size(); i++) {
116           Edge& e = edges[G[x][i]];
117           if(e.cap > e.flow) m = min(m, d[e.to]);
118         }
119         if(--num[d[x]] == 0) break;
120         num[d[x] = m+1]++;
121         cur[x] = 0;
122         if(x != s) x = edges[p[x]].from;
123       }
124     }
125     return flow;
126   }
127 };
128 
129 
130 ISAP g;
131 
132 double get_dist(Point p1, Point p2) {
133     return sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) );
134 }
135 
136 int main() {
137     int t;
138     int n; double d;
139    // freopen("a.txt","r",stdin);
140     scanf("%d",&t);
141     while(t--) {
142         scanf("%d %lf",&n, &d);
143         int sum = 0;
144         for(int i = 0; i < n; i++) {
145             scanf("%d %d %d %d",&point[i].x, &point[i].y, &point[i].ni, &point[i].mi);
146             sum += point[i].ni;
147         }
148         //Dinic g;
149         g.ClearAll(maxn);
150         for(int i = 0; i < n; i++) {
151             int left = i + 1; int right = n + left;
152             g.AddEdge(0, left, point[i].ni);
153             g.AddEdge(left, right, point[i].mi);
154             g.AddEdge(right, left, point[i].mi);
155             for(int j = i + 1; j < n; j++) {
156                 if( i == j)
157                     continue;
158                 if(d - get_dist(point[i], point[j]) > 0.00001) {
159                     g.AddEdge(right, j + 1, INF);
160                     g.AddEdge(j + 1 + n, left, INF);
161                 }
162             }
163         }
164         //printf("*%d\n",sum);
165         int c = 0;
166         for(int i = 0; i < n; i++) {
167             int s = 0; int t = i + 1;
168             g.init();
169             if(g.MaxFlow(s, t, INF) == sum)
170             printf(c++ ? " %d" : "%d",i);
171             //printf("%d\n",g.MaxFlow(s, t));
172         }
173         if(c == 0)
174         printf("-1");
175         puts("");
176     }
177     return 0;
178 }
View Code

 

 

posted @ 2014-05-23 20:40  悠悠我心。  阅读(344)  评论(0编辑  收藏  举报