Sgu 438 The Glorious Karlutka River(动态流)

题目地址: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;
}





你可能感兴趣的:(网络流_最大流,ACM)