题目地址:http://acm.sgu.ru/problem.php?contest=0&problem=438
思路:
1.由于不同时刻,两点的流量不同,故不能在一张图中求解。
2.由于任意时刻,人可在中间节点停留,故费用流无法解决此题。
3.给定所有流量限制,求最短经过时间。可通过枚举时间,将中间节点按时间拆点为(i,t)(即在时间t时的点i)。
(1)节点存在容量限制,可通过拆点解决:对于点i,连边(i,t)->(i',t),容量为c[i],仍处于该点时间不变。
(2)若能从i点一次跳到j点,则连边(i',t)->(j,t+1),容量为INF,代表在时间t当前处于i的点,下一秒可到达j点。
(3)对于所有能从岸边一次到达的点,连边S->(i,t);对于能一次到达岸边的点,连边(i',t)->T。
(4)每次在原图的基础上添加点与边,每次在残量网络中求最大流,也即为时间t时通过人数,累加直到总人数大于等于m时的时间即为最小时间。
4.最大时间为n+m:每个点只能留一人,每个人经过每个点的时间。
#include
#include
#include
#include
#include
#include
#include
#define debug
using namespace std;
const int maxn = 25000 + 50;
const int maxm = 5000 + 50;
const int INF = 0x3f3f3f3f;
struct edge
{
int to, nt;
};
struct Node
{
int x, y, c;
};
struct Edge
{
int from, to, cap, flow;
Edge(int a, int b, int c, int d) :from(a), to(b), cap(c), flow(d) {}
};
struct Dinic
{
int n, m, s, t;
vector edges;
vector G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n)
{
this->n = n;
for (int i = 0; i <= n; i++) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
bool BFS()
{
memset(vis, 0, sizeof(vis));
queue Q;
Q.push(s);
vis[s] = 1;
d[s] = 0;
while (!Q.empty())
{
int x = Q.front();
Q.pop();
for (int i = 0; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
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 = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
{
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
int MaxFlow(int s, int t)
{
this->s = s;
this->t = t;
int flow = 0;
while (BFS())
{
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
};
Dinic g;
Node a[55];
int head[55];
edge edges[maxm];
int n, m, d, w, tot, S, T;
void addEdge(int u, int v)
{
edges[tot].to = v, edges[tot].nt = head[u], head[u] = tot++;
}
double dist(Node a, Node b)
{
return sqrt(1.0*(a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
int main()
{
#ifdef debu
freopen("in.txt", "r", stdin);
#endif // debug
int f1 = 0, f2 = 0;
memset(head, -1, sizeof(head));
scanf("%d%d%d%d", &n, &m, &d, &w);
S = 0, T = 401 * n + 2;
for (int i = 1; i <= n; i++)
{
scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].c);
if (a[i].y <= d)
{
f1 = 1, addEdge(0, i);
}
if (a[i].y + d >= w)
{
f2 = 1, addEdge(n + 1, i);
}
}
if (w <= d) printf("1\n");
else
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if ((i != j) && dist(a[i], a[j]) <= d)
{
addEdge(i, j);
}
}
}
int ans = -1, tot = 0;
if (f1&&f2)
{
for (int t = 1; t <= n + m; t++)
{
for (int i = head[0]; ~i; i = edges[i].nt)
{
int nt = edges[i].to;
g.addEdge(S, (t - 1)*n + 1 + nt, INF);
}
for (int i = head[n + 1]; ~i; i = edges[i].nt)
{
int nt = edges[i].to;
g.addEdge((200 + t)*n + 1 + nt, T, INF);
}
for (int i = 1; i <= n; i++)
{
g.addEdge((t - 1)*n + 1 + i, (200 + t)*n + 1 + i, a[i].c);
for (int j = head[i]; ~j; j = edges[j].nt)
{
int nt = edges[j].to;
g.addEdge((200 + t)*n + 1 + i, t*n + 1 + nt,INF);
}
}
tot += g.MaxFlow(S, T);
if (tot >= m)
{
ans = t + 1;
break;
}
}
}
if (ans == -1) printf("IMPOSSIBLE\n");
else printf("%d\n", ans);
}
return 0;
}