題目地址: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<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#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<Edge> edges;
vector<int> 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<int> 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;
}