杨柳

题目

传送门

题意

给出一个\(r * c\)的矩阵, 有\(n\)颗棋子, 给出棋子的初始位置, 有\(n\)个目标点, 有些位置不能走, 位于\((x, y)\)的棋子, 可以一步走到\((x + a, y + b)\), \((x - a, y + b)\), \((x + a, y - b)\), \((x - a, y + b)\), \((x + b, y + a)\), \((x + b, y - a)\), \((x - b, y + a)\). \((x - b, y - a)\), 求每个棋子都走到目标点的最短时间。

题解

由源点向棋子的初始位置连容量为\(1\)费用为\(0\)的边
由目标位置向汇点连容量为\(1\)用为\(0\)的边
对于每一个能走的点, 向他能够一步走到的点连容量为\(\infty\)费用为\(1\)的边
然后跑费用流

此题卡常, 如果用MCMF的话要多路增广才能过。

代码

#include <iostream>
#include <cstdlib>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;


const int N = 10010, M = 160010;

const int INF = 0x2A2A2A2A;


struct edge
{
	int from, to, flow, cap, dis;
	edge() { }
	edge(int _1, int _2, int _3, int _4, int _5) : from(_1), to(_2), flow(_3), cap(_4), dis(_5) { }
};

struct MCMF
{
	int head[N], nxt[M], tot;
	edge edges[M];

	inline void init()
	{
		memset(head, -1, sizeof(head));
		tot = 0;
	}
	
	inline void add_edge(int x, int y, int z, int k)
	{
		edges[tot] = edge(x, y, 0, z, k);
		nxt[tot] = head[x];
		head[x] = tot++;
		edges[tot] = edge(y, x, 0, 0, -k);
		nxt[tot] = head[y];
		head[y] = tot++;
	}

	int s, t;

	int L, R;

	int cost;
	int flow;

	int dist[N];
	bool inq[N];

	bool SPFA()
	{
		memset(dist + L, 127 / 3, sizeof(int) * (R - L + 1));
		memset(inq + L, 0, sizeof(int) * (R - L + 1));
		
		queue<int> q;
		q.push(s);
		dist[s] = 0;
		inq[s] = 1;
		
		while (!q.empty())
		{
			int x = q.front(); q.pop();
			inq[x] = 0;
			cur[x] = head[x];
			for (register int i = head[x]; ~i; i = nxt[i])
			{
				edge & e = edges[i];
				if (e.flow < e.cap && dist[e.to] > dist[x] + e.dis)
				{
					dist[e.to] = dist[x] + e.dis;
					if (!inq[e.to])
						inq[e.to] = 1, q.push(e.to);
				}
			}
		}
		
		return dist[t] != INF;
	}
	
	bool vis[N];
	
	int cur[N];
	
	int dfs(int x, int a)
	{
		if (x == t || a == 0) return a;
		
		vis[x] = 1;
		
		int flow = 0, f;
		
		for (int & i = cur[x]; ~i; i = nxt[i])
		{
			edge & e = edges[i];
			if (vis[e.to]) continue;
			if (dist[e.to] == dist[x] + e.dis && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
			{
				e.flow += f;
				edges[i^1].flow -= f;
				cost += e.dis * f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		
		vis[x] = 0;
		
		return flow;
	}

	pair<int, int> mincostmaxflow(int _s, int _t)
	{
		cost = 0;
		flow = 0;
		s = _s, t = _t;
		while (SPFA())
			flow += dfs(s, INF);
		return make_pair(flow, cost);
	}
} solve;


char mp[110][110];

int n, m;
int k, A, B;


inline int getid(int x, int y) { return (x-1) * m + y; }


int main()
{
	scanf("%d %d %d %d %d", &n, &m, &k, &A, &B);
	
	int S = n * m + 1, T = n * m + 2;
	
	solve.init();
	solve.L = 0, solve.R = n * m + 2;
	
	for (register int i = 1; i <= n; i++)
		scanf("%s", mp[i] + 1);
	
	for (register int i = 1; i <= k; i++)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		solve.add_edge(getid(x, y), T, 1, 0);
	}
	
	for (register int i = 1; i <= k; i++)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		solve.add_edge(S, getid(x, y), 1, 0);
	}
	
	for (register int x = 1; x <= n; x++)
		for (register int y = 1; y <= m; y++)
			if (mp[x][y] == '.')
			{
				if (x + A <= n && y + B <= m && mp[x + A][y + B] == '.')
				{	solve.add_edge(getid(x, y), getid(x + A, y + B), INF, 1);
					solve.add_edge(getid(x + A, y + B), getid(x, y), INF, 1);
				}
				if (x + A <= n && y - B >= 1 && mp[x + A][y - B] == '.')
				{	solve.add_edge(getid(x, y), getid(x + A, y - B), INF, 1);
					solve.add_edge(getid(x + A, y - B), getid(x, y), INF, 1);
				}
				if (x + B <= n && y + A <= m && mp[x + B][y + A] == '.')
				{	solve.add_edge(getid(x, y), getid(x + B, y + A), INF, 1);
					solve.add_edge(getid(x + B, y + A), getid(x, y), INF, 1);
				}
				if (x + B <= n && y - A >= 1 && mp[x + B][y - A] == '.')
				{	solve.add_edge(getid(x, y), getid(x + B, y - A), INF, 1);
					solve.add_edge(getid(x + B, y - A), getid(x, y), INF, 1);
				}
			}
	
	pair<int, int> Ans = solve.mincostmaxflow(S, T);
	
	if (Ans.first == k) printf("%d\n", Ans.second);
	else puts("-1");
	
	return 0;
}
posted @ 2018-11-26 20:07  EZ_WYC  阅读(139)  评论(0编辑  收藏  举报