HDU-2732 (Leapin' Lizards) 网络流

网络流真的博大精深

题意:
在一个迷宫中,新进了一批小蜥蜴. 然而因为一些原因,出口被封住了,而且迷宫燃起了大火,现在小蜥蜴们急着离开,想要求助于ACMer们,哈哈……
把蜥蜴所在的坐标当做一根有高度为k的柱子,现在每有一只蜥蜴跳出格子,格子的柱子高度就会减少一,直到为0,表示这个格子不能在通过蜥蜴. 题目规定,小蜥蜴们可以从当前格子往周围跳出小于等于d距离的长度.当蜥蜴跳出迷宫的边界,就算这只蜥蜴存活下来了,而那些不能逃出去的,就只能等着被烤成烤肉了.现在想要让更多的蜥蜴逃出,求最后剩下的蜥蜴数;

题解:
这道题目有很深的网络流味道…….,具体建模还是基本的网络流模式,就是虚拟出源点和汇点,再把一些相关联的点通过边和流量联系起来. 具体看下我写的代码吧! 里面有解释具体怎么建边.

    /* *********************************************** Author :xdlove Created Time :2015年08月18日 星期二 13时18分54秒 File Name :xd.cpp ************************************************ */

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

/******************************** please don't hack me!! /(ToT)/~~ __------__ /~ ~\ | //^\\//^\| /~~\ || T| |T|:~\ | |6 ||___|_|_||:| \__. / o \/' | ( O ) /~~~~\ `\ \ / | |~~\ | ) ~------~`\ /' | | | / ____ /~~~)\ (_/' | | | /' | ( | | | | \ / __)/ \ \ \ \ \/ /' \ `\ \ \|\ / | |\___| \ | \____/ | | /^~> \ _/ < | | \ \ | | \ \ \ -^-\ \ | ) `\_______/^\______/ ************************************/

const int MAXN = 3e3 + 5;//点数的最大值
const int MAXM = 1e6 + 5;//边数的最大值
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow;
} edge[MAXM]; //注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
void init()
{
    tol = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0)
{
    //printf("%d %d %d\n",u,v,w);
    edge[tol].to = v;
    edge[tol].cap = w;
    edge[tol].flow = 0;
    edge[tol].next = head[u];
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cap = rw;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}
int Q[MAXN];
void BFS(int start,int end)
{
    memset(dep,-1,sizeof(dep));
    memset(gap,0,sizeof(gap));
    gap[0] = 1;
    int front = 0, rear = 0;
    dep[end] = 0;
    Q[rear++] = end;
    while(front != rear)
    {
        int u = Q[front++];
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(dep[v] != -1)continue;
            Q[rear++] = v;
            dep[v] = dep[u] + 1;
            gap[dep[v]]++;
        }
    }
}
int S[MAXN];
int sap(int start,int end,int N)
{
    BFS(start,end);
    memcpy(cur,head,sizeof(head));
    int top = 0;
    int u = start;
    int ans = 0;
    while(dep[start] < N)
    {
        if(u == end)
        {
            int Min = INF;
            int inser;
            for(int i = 0; i < top; i++)
                if(Min > edge[S[i]].cap - edge[S[i]].flow)
                {
                    Min = edge[S[i]].cap - edge[S[i]].flow;
                    inser = i;
                }
            for(int i = 0; i < top; i++)
            {
                edge[S[i]].flow += Min;
                edge[S[i]^1].flow -= Min;
            }
            ans += Min;
            top = inser;
            u = edge[S[top]^1].to;
            continue;
        }
        bool flag = false;
        int v;
        for(int i = cur[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].to;
            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])
            {
                flag = true;
                cur[u] = i;
                break;
            }
        }
        if(flag)
        {
            S[top++] = cur[u];
            u = v;
            continue;
        }
        int Min = N;
        for(int i = head[u]; i != -1; i = edge[i].next)
            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
            {
                Min = dep[edge[i].to];
                cur[u] = i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])return ans;
        dep[u] = Min + 1;
        gap[dep[u]]++;
        if(u != start)u = edge[S[--top]^1].to;
    }
    return ans;
}

char s[22][22],t[22][22];

struct Point 
{
    int x,y,v;
    Point(){

    }
    Point(int _x,int _y,int _v)
    {
        x = _x;
        y = _y;
        v = _v;
    }
    bool operator == (const Point &a) const
    {
        return x == a.x && y == a.y;
    }
}p[MAXN];

int mul(int x)
{
    return x * x;
}

int dist(Point a,Point b)
{
    return  mul(a.x - b.x) + mul(a.y - b.y);
}


int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T,kcase = 0;
    int n,m,d;
    cin>>T;
    while(T--)
    {
        init();
        scanf("%d %d",&n,&d);
        d *= d;
        for(int i = 0; i < n; i++)
            scanf("%s",s[i]);
        for(int i = 0; i < n; i++)
            scanf("%s",t[i]);
        int ss,tt,tot = 0;
        int num = 0;
        m = strlen(s[0]);
        tt = 2 * n * m + 2;
        ss = tt - 1;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                if(t[i][j] == 'L')
                {
                    num++;
                    addedge(ss,i * m + j,1); //对于每只蜥蜴来说,从源点往其建一流量为1的边,表示他能否逃出去;
                }
                if(s[i][j] != '0')
                {
                    p[tot++] = Point(i,j,i * m + j);
                    addedge(i * m + j,n * m + i * m + j,s[i][j] - '0');//对于每一个有柱子的格子来说,自己与自己连一条容量为其键值key的边,
                                                                        //表示其最多只能通过key只蜥蜴;
                }
            }
        }
        //每个格子相互的连边
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                Point nn = Point(i,j,0);
                for(int k = 0; k < tot; k++)
                {
                    int pd = dist(nn,p[k]);
                    if(i == 0 || j == 0 || i == n - 1 || j == m - 1)
                    {
                        if(pd < d) //对于边界点来说,如果距离之和小于d,则当前蜥蜴可以从这个格子逃出;
                            addedge(n * m + p[k].v,tt,INF);//所以往汇点建一条流量为无穷大的边,表示可以从这个格子逃出的蜥蜴数量不确定,取大一点的值;
                    }
                    if(s[i][j] == '0' || (nn == p[k])) continue;//key=0或者自己,不建边
                    if(pd <= d) 
                        addedge(n * m + p[k].v,i * m + j,INF);//相邻两个格子之间可以通过无穷只蜥蜴,在没有key值限制的情况下;
                }
            }
        }
        int ans = sap(ss,tt,2 * n * m + 2);
        ans = num - ans;
        printf("Case #%d: ",++kcase);
        if(ans) printf("%d ",ans);
        else printf("no ");
        if(ans > 1) printf("lizards were ");
        else printf("lizard was ");
        puts("left behind.");
    }
    return 0;
}

你可能感兴趣的:(网络流建模)