Bzoj P1066 [SCOI2007]蜥蜴___網路流
阿新 • • 發佈:2018-12-21
題目大意:
在一個的矩陣中有一些高度不同的石柱,某些石柱上可能站著一個蜥蜴。 行列中相鄰石柱的距離為,蜥蜴可以跳到平面距離不超過的任何一個石柱上。 每次蜥蜴跳躍離開以後,所離開的石柱高度減,到達的石柱高度不變。 若該石柱原來高度為,則蜥蜴離開後消失,以後其他蜥蜴不能落腳。 任何時刻不能有兩隻蜥蜴在同一個石柱上。 你的任務是讓儘量多的蜥蜴逃到邊界外。 問無法逃離的蜥蜴總數的最小值。
分析:
答案其實可以寫成 那麼我們可以考慮建模求出最大蜥蜴逃出總數, ①對於某一個點 我們就可以拆成2個點與, 令連向,容量為石柱高度的邊,這樣過去了多少,就是用掉了石柱的多少高度,也就是有多少個蜥蜴已經經過完這個石柱
然後我們設源點為,匯點為, ②需要向所有初始狀態下存在蜥蜴的點連一條到容量為的邊,因為蜥蜴是從這個點開始的,如果離開以後,需要消耗了1點高度
③對於所有能一步離開的點,都向連一條容量為無窮大(或)的邊 ④對於任意兩個能到達的點 向連一條容量為無窮大(或者)的邊 然後跑一遍網路流求出最大逃出總數 然後就可以求出答案了
程式碼:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <algorithm>
#define inf 0x3f3f3f3f
#define N 25
using namespace std;
struct Node { int To, w, nxt; }e[200005];
int A[N][N], dis[2*N*N], ls[2*N*N], n, m, d, cnt = 1, tot = 0, Total = 0, Maxflow = 0, S, T;
char s[N];
int Numid(int x, int y)
{
return (x - 1) * m + y;
}
void Addedge(int u, int v, int w)
{
e[++cnt].To = v, e[cnt].nxt = ls[u], e[cnt].w = w, ls[u] = cnt;
e[++cnt].To = u, e[cnt].nxt = ls[v], e[cnt].w = 0, ls[v] = cnt;
}
bool Checkjl(int ax, int ay, int bx, int by)
{
return (((ax - bx) * (ax - bx) + (ay - by) * (ay - by)) <= (d * d));
}
queue <int> Q;
bool bfs()
{
while (Q.size()) Q.pop();
for (int i = S; i <= T; i++) dis[i] = 0;
dis[S] = 1;
Q.push(S);
while (Q.size())
{
int u = Q.front(); Q.pop();
for (int i = ls[u]; i; i = e[i].nxt)
if (e[i].w && !dis[e[i].To])
{
dis[e[i].To] = dis[u] + 1;
if (e[i].To == T) return 1;
Q.push(e[i].To);
}
}
return 0;
}
int dfs(int u, int flow)
{
if (u == T) return flow;
int rest = flow, rp = 0;
for (int i = ls[u]; i && rest; i = e[i].nxt)
if (dis[e[i].To] == dis[u] + 1 && e[i].w)
{
rp = dfs(e[i].To, min(rest, e[i].w));
if (!rp) dis[e[i].To] = 0;
e[i].w -= rp;
e[i^1].w += rp;
rest -= rp;
}
return flow - rest;
}
void dinic()
{
int flow;
while (bfs())
while (flow = dfs(S, inf)) Maxflow += flow;
}
int main()
{
scanf("%d %d %d", &n, &m, &d);
S = 0, T = 2 * n * m + 1;
for (int i = 1; i <= n; i++)
{
scanf("%s", s + 1);
for (int j = 1; j <= m; j++)
{
A[i][j] = s[j] - '0';
if (i - d <= 0 || i + d > n || j - d <= 0 || j + d > m) Addedge(Numid(i, j) + n * m, T, inf);
if (A[i][j]) Addedge(Numid(i, j), Numid(i, j) + n * m, A[i][j]);
}
}
for (int i = 1; i <= n; i++)
{
scanf("%s", s + 1);
for (int j = 1; j <= m; j++)
if (s[j] == 'L') ++Total, Addedge(S, Numid(i, j), 1);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
for (int k = max(i - d, 1); k <= min(i + d, n); k++)
for (int l = max(j - d, 1); l <= min(j + d, m); l++)
if (A[i][j] && A[k][l] && (i != k || j != l))
if (Checkjl(i, j, k, l)) Addedge(Numid(i, j) + n * m, Numid(k, l), inf);
dinic();
printf("%d\n", Total - Maxflow);
return 0;
}