杨柳
题目
题意
给出一个\(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;
}