SGU 438 The Glorious Karlutka River =) 拆点+动态流+最大流

                        The Glorious Karlutka River =)

Time Limit:500MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

Submit Status Practice SGU 438

Appoint description:

Description

A group of Mtourists
are walking along the Karlutka river. They want to cross the river, but
they couldn‘t find a bridge. Fortunately, there are some piles of
rubbish floating in the water, and the tourists have decided to try to cross the river by jumping from one pile to another.

A tourist can move up to D meters in any direction at one jump. One jump takes exactly one second.
tourists know that the river is W meters wide, and they have estimated the coordinates of rubbish piles (
Xi,
Yi) and the capacity of each pile (
Ci, the maximum number of tourists
that this pile can hold at the same time). Rubbish piles are not very
large and can be represented as points. The river flows along the X axis.
tourists start on the river bank at 0 by Y axis. The Y coordinate of the opposite bank is W.

tourists would like to know if they can get to the opposite bank of the river, and how long it will take.

Input

First line of input consists of four integers: number of rubbish piles N (0 ≤
N ≤ 50), number of tourists M (0 <
M ≤ 50), maximum length of tourist‘s jump D (0 ≤
D ≤ 1000), and width of the river W (0 <
W ≤ 1000) Following N lines describe the rubbish piles, each line consists of three integers: (0 <
Xi < 1000, 0 <
Yi <
W, 0 ≤
Ci ≤ 1000) — pile coordinates and capacity.

Output

Output a single number indicating the minimal time (in seconds) in which all tourists will be able to cross the river, or the line "
IMPOSSIBLE" if it is impossible to cross the river.

Sample Input

sample input
sample output
3 10 3 7
0 2 2
4 2 2
2 4 3
6
sample input
sample output
3 10 3 8
0 2 2
4 2 2
2 4 3
IMPOSSIBLE

题意:

给出一条河,宽为W,并建立坐标系,河沿着x轴流动。从原点开始。宽为y轴。

现在给出河上的N个点的坐标和容量,通过这些点可以过河,已知有M个人。每个人每次可以往任意方向跳D米。

每次跳花费1秒。问最少多少时间能使全部人过河。如果不可能则输出“IMPOSSIBLE”。

思路:

首先以游客在的河岸为源点,对岸为汇点。

对于每个点容量的限制,需要拆点,把每个点i拆成点i和点i,中间连接一条容量为ci的边。

因为加入了时间限制,所以要按时间将每个石头拆点。

可以知道如果有N个石头和M个人,如果能够过河,最多花费的时间为N+M。所以从1开始枚举T一直到N+M。

T=1的时候,将离游客所在的河岸距离<=D的石子i与汇点连边,容量为正无穷。

T>1的时候,仍将离游客所在的河岸距离<=D的石子i与汇点连边,容量为正无穷。

需要注意的是,应该此时将T-1时刻离对岸距离<=D的石子i与汇点连边,容量为正无穷。表示的是T-1时刻在第i个石头上,花了一秒跳到了对岸,此时时刻为T。

并且将T-1时刻和T时刻距离小于等于D的石头连边,表示的是T-1时刻在i个石头上,花了一秒跳到了j个石头,此时时刻为T。容量为正无穷。

对每秒求最大流,累加每秒钟通过的人数和,当人数>=M时则跳出。

  1 //#include <bits/stdc++.h>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <vector>
  8 #include <queue>
  9 using namespace std;
 10 #define maxn 10010
 11 const int inf = 0x3f3f3f3f;
 12 int N, M, D, W;
 13 struct Edge
 14 {
 15     int from, to, cap, flow;
 16     Edge(int f, int t, int c, int fl)
 17     {
 18         from = f; to = t; cap = c; flow = fl;
 19     }
 20 };
 21 struct Piles
 22 {
 23     double x, y;
 24     int c;
 25     Piles(double xx, double yy, int cc)
 26     {
 27         x = xx; y = yy; c = cc;
 28     }
 29     Piles(){}
 30 }p[55];
 31 vector <Edge> edges;
 32 vector <int> G[maxn];
 33 int n, m, s, t;
 34 void AddEdge(int from, int to, int cap)
 35 {
 36     edges.push_back(Edge(from, to, cap, 0));
 37     edges.push_back(Edge(to, from, 0, 0));
 38     m = edges.size();
 39     G[from].push_back(m-2);
 40     G[to].push_back(m-1);
 41 }
 42 int vis[maxn], cur[maxn], d[maxn];
 43 int cntnow;
 44 bool bfs()
 45 {
 46     memset(vis, 0, sizeof(vis));
 47     d[s] = 0; vis[s] = 1;
 48     queue <int> q;
 49     q.push(s);
 50     while(!q.empty())
 51     {
 52         int u = q.front(); q.pop();
 53         for(int i = 0; i < G[u].size(); i++)
 54         {
 55             Edge &e = edges[G[u][i]];
 56             if(!vis[e.to] && e.cap > e.flow)
 57             {
 58                 vis[e.to] = 1;
 59                 d[e.to] = d[u]+1;
 60                 q.push(e.to);
 61             }
 62         }
 63     }
 64     return vis[t];
 65 }
 66 int dfs(int x, int a)
 67 {
 68     if(x == t || a == 0) return a;
 69     int flow = 0, f;
 70     for(int &i = cur[x]; i < G[x].size(); i++)
 71     {
 72         Edge &e = edges[G[x][i]];
 73         if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(e.cap-e.flow, a))) > 0)
 74         {
 75             e.flow += f;
 76             edges[G[x][i]^1].flow -= f;
 77             flow += f;
 78             a -= f;
 79             if(a == 0) break;
 80         }
 81     }
 82     return flow;
 83 }
 84 int MaxFlow()
 85 {
 86     int flow = 0;
 87     while(bfs())
 88     {
 89         memset(cur, 0, sizeof(cur));
 90         flow += dfs(s, inf);
 91     }
 92     return flow;
 93 }
 94 int mp[55][55];
 95 double dist(Piles p1, Piles p2)
 96 {
 97     return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
 98 }
 99 int main()
100 {
101     while(~scanf("%d%d%d%d", &N, &M, &D, &W))
102     {
103         edges.clear();
104         for(int i = 0; i <= N*2*(N+M)+1; i++) G[i].clear();
105         for(int i = 1; i <= N; i++)
106         {
107             scanf("%lf%lf%d", &p[i].x, &p[i].y, &p[i].c);
108         }
109         if(D >= W)
110         {
111             printf("1\n"); continue;
112         }
113         memset(mp, 0, sizeof(mp));
114         for(int i = 1; i <= N; i++)
115         {
116             for(int j = 1; j <= N; j++)
117             {
118                 if(dist(p[i], p[j]) <= D) mp[i][j] = mp[j][i] = 1;
119             }
120         }
121
122         s = 0; t = N*2*(N+M)+1;
123         for(int i = 1; i <= N; i++)
124         {
125             if(p[i].y <= D) AddEdge(s, i, inf);
126             AddEdge(i, i+N, p[i].c);
127         }
128
129         bool flag = false;
130         int sum = 0;
131         for(int T = 2; T <= N+M; T++)
132         {
133             for(int i = 1; i <= N; i++)
134             {
135                 if(p[i].y <= D) AddEdge(s, (T-1)*2*N+i, inf);
136                 if(W-p[i].y <= D) AddEdge((T-2)*2*N+i+N, t, inf);
137                 AddEdge((T-1)*2*N+i, (T-1)*2*N+i+N, p[i].c);
138
139                 for(int j = 1; j <= N; j++)
140                 {
141                     if(mp[i][j])
142                     {
143                         AddEdge((T-2)*2*N+j+N, (T-1)*2*N+i, inf);
144                     }
145                 }
146             }
147             int flow = MaxFlow();
148             sum += flow;
149             if(sum >= M)
150             {
151                 flag = true;
152                 printf("%d\n", T);
153                 break;
154             }
155         }
156         if(flag == false)
157         {
158             printf("IMPOSSIBLE\n");
159         }
160
161     }
162     return 0;
163 }
时间: 2024-08-05 11:11:31

SGU 438 The Glorious Karlutka River =) 拆点+动态流+最大流的相关文章

SGU 438 The Glorious Karlutka River =) 动态流

题目大意:有一条东西向流淌的河,宽为W,河中有N块石头,每块石头的坐标(Xi, Yi)和最大承受人数Ci已知.现在有M个游客在河的南岸,他们想穿越这条河流,但是每个人每次最远只能跳D米,每跳一次耗时1秒.问他们能否全部穿越这条河流,如果能,最少需要多长时间.(0 <= N <= 50, 0 < M <= 50, 0 <= D <= 1000, 0 < W <= 1000, 0 < Xi < 1000, 0 < Yi < W, 0 &l

SGU438_The Glorious Karlutka River =)

好题,有一些人在河的一边,想通过河里的某些点跳到对岸去.每个点最多只能承受一定数量的人,每人跳跃一次需要消耗一个时间.求所有人都过河的最短时间. 看网上说是用了什么动态流的神奇东东.其实就是最大流吧,不过是一个很有意思的模型. 每递增一个时间,所有的点增加一层,因为有的人可以站在上一个点不走动,最终每个点分别表示河中的某个点在某个特定的时刻. 同时为了保证人数在点的承受范围之内,拆点即可. 一直增加层数,直到最大流达到m为止即可. 召唤代码君: #include <iostream> #inc

SGU438 The Glorious Karlutka River =)(最大流)

题目大概说有m个人要过一条宽W的河,人最远跳远距离是d,河上有n个垃圾堆,每个垃圾堆都有坐标和同一时间能容纳的人数,问所有人最少要跳几次才能跳到对岸. 又是一题根据时间拆点的最大流. 二分时间建容量网络判定:按时间对每个垃圾堆拆点,再拆成两点中间连容量为同一时间能容纳的人数的边,所有t时刻的点向所有能到达的t+1时刻的点连边. 另外,可以知道的是如果能到对岸那最坏情况总共需要跳n+m.因为最坏情况每个垃圾堆只能容纳一人,且必须跳完所有垃圾堆才能到达对岸,那么第一个人需要跳m+1次,后面n-1人紧

HDU 3277Marriage Match III(二分+并查集+拆点+网络流之最大流)

题目地址:HDU 3277 这题跟这题的上一版建图方法差点儿相同,仅仅只是须要拆点.这个点拆的也非常巧妙,既限制了流量,还仅仅限制了一部分,曾经一直以为拆点会所有限制,原来也能够用来分开限制,学习了. 建图方法为:建一源点与汇点,将女孩进行拆点,拆成i和i+n,将i与源点连边,权值为mid,将i与i+n连边,权值为k,再将男孩与汇点连边,权值为mid,这时能够配对的就将i与相应的男孩连边,权值为1,不能配对的就将i+n与相应的男孩连边,这种话对原来可配对的不会限制流量,对不能够配对的限制了流量k

UVa 2197 &amp; 拆点分环费用流

题意: 给你一个带权有向图,选择一些边组成许多没有公共边的环,使每个点都在k个环上,要求代价最小. SOL: 现在已经养成了这种习惯,偏题怪题都往网络流上想... 怎么做这题呢... 对我们看到每个点都在k个环上,而且没有公共边,那么很显然每个点的入度出度都为k.   然后我们拆点,建源汇ST,S与每个入点连边容量为k,出点与汇点相连容量为k,费用为0,如果城市i,j之间有边那么将i的入点和j的出点连一条费用为权,容量为1的边.然后跑一遍费用流.如果每条边都满流那么就有解. 好神奇...从环变成

HDU 3395 Special Fish(拆点+最大费用最大流)

Special Fish Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2367    Accepted Submission(s): 878 Problem Description There is a kind of special fish in the East Lake where is closed to campus o

hdu 1853(拆点判环+费用流)

Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others)Total Submission(s): 2257    Accepted Submission(s): 1148 Problem Description There are N cities in our country, and M one-way roads connecting them. Now L

sgu 176 Flow construction(有源汇的上下界最小流)

[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足流量平衡的最小流量. [思路] 按照可行流构造网络.不连t->s的边先跑一遍附加源汇点的最大流,然后连t->s一条inf边,在残量网络上跑一遍最大流.第一次求最大流所以能走的边都已经流满,第二次求附加源汇点最大流t->s的流量就会尽可能小. 另外还可以二分下界mid,然后连边(T,S,mid

网络流专栏

最大流 POJ 1273 Drainage Ditches POJ 1274 The Perfect Stall (二分图匹配) POJ 1698 Alice's Chance(构图) POJ 1459 Power Network(构图) POJ 2112 Optimal Milking (二分) POJ 2455 Secret Milking Machine (二分) POJ 3189 Steady Cow Assignment (枚举) POJ 1637 Sightseeing tour (