1. 程式人生 > >Bzoj P1066 [SCOI2007]蜥蜴___網路流

Bzoj P1066 [SCOI2007]蜥蜴___網路流

題目大意:

在一個nmn*m的矩陣中有一些高度不同的石柱,某些石柱上可能站著一個蜥蜴。 行列中相鄰石柱的距離為11,蜥蜴可以跳到平面距離不超過dd的任何一個石柱上。 每次蜥蜴跳躍離開以後,所離開的石柱高度減11,到達的石柱高度不變。 若該石柱原來高度為11,則蜥蜴離開後消失,以後其他蜥蜴不能落腳。 任何時刻不能有兩隻蜥蜴在同一個石柱上。 你的任務是讓儘量多的蜥蜴逃到邊界外。 問無法逃離的蜥蜴總數的最小值。

1<=n,m<=20,1<=d<=41<=n,m<=20, 1<=d<=4

分析:

答案其實可以寫成蜥蜴總數-最大逃出總數 那麼我們可以考慮建模求出最大蜥蜴逃出總數, ①對於某一個點(i,j)(i,j) 我們就可以拆成2個點m(i1)+jm*(i-1)+jm(i1)+j+nmm*(i-1)+j+n*m, 令m(i1)+jm*(i-1)+j連向m(i1)+j+nmm*(i-1)+j+n*m,容量為石柱高度a[i][j]a[i][j]的邊,這樣過去了多少,就是用掉了石柱的多少高度,也就是有多少個蜥蜴已經經過完這個石柱

然後我們設源點為SS,匯點為TT, ②SS需要向所有初始狀態下存在蜥蜴的點(xi,yi)(x_i,y_i)連一條SSm(xi1)+yim*(x_i-1)+y_i容量為11的邊,因為蜥蜴是從這個點開始的,如果離開以後,需要消耗了1點高度

③對於所有能一步離開的點(xi,yi)(x_i,y_i),都向TT連一條容量為無窮大(或a[xi][yi]a[x_i][y_i])的邊 ④對於任意兩個能到達的點(x1,y1)(x2,y2)(x1,y1),(x2,y2) m(x

11)+y1+nmm*(x1-1)+y1+n*mm(x21)+y2m*(x2-1)+y2連一條容量為無窮大(或者a[x1][y1]a[x1][y1])的邊 然後跑一遍網路流求出最大逃出總數 然後就可以求出答案了

程式碼:

#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;
}