hlg1512March of the Penguins【无向图+拆点】
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.
|
||||||
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 }