LA 6474 Drop Zone 解题报告

题目链接

  要添最少的挡板使所有的‘D‘不存在到达网格外的路径.

以每个格子向四个方向中可以到达的格子连容量为1的边, 从源点向所有‘D‘ 连容量为4的边,网格外的点向汇点连一条容量为4的边.

答案就是这个容量网络的最小割,即最大流.

/*
      最大流SAP
      邻接表
      思路:基本源于FF方法,给每个顶点设定层次标号,和允许弧。
      优化:
      1、当前弧优化(重要)。
      1、每找到以条增广路回退到断点(常数优化)。
      2、层次出现断层,无法得到新流(重要)。
      时间复杂度(m*n^2)
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <utility>
#include <vector>
#define ms(a,b) memset(a,b,sizeof a)
using namespace std;
const int INF = 6111;
struct node {
    int v, c, next;
} edge[100000];
int  pHead[100000], SS, ST, nCnt;
int n, m;
int g[200][200];
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
//同时添加弧和反向边, 反向边初始容量为0
void addEdge (int u, int v, int c) {
    edge[++nCnt].v = v; edge[nCnt].c = c, edge[nCnt].next = pHead[u]; pHead[u] = nCnt;
    edge[++nCnt].v = u; edge[nCnt].c = 0, edge[nCnt].next = pHead[v]; pHead[v] = nCnt;
}
inline int SAP (int pStart, int pEnd, int N) {
    //层次点的数量  点的层次   点的允许弧     当前走过边的栈
    int numh[INF], h[INF], curEdge[INF], pre[INF];
    //当前找到的流, 累计的流量, 当前点, 断点, 中间变量
    int cur_flow, flow_ans = 0, u, neck, i, tmp;
    //清空层次数组,
    ms (h, 0); ms (numh, 0); ms (pre, -1);
    //将允许弧设为邻接表的任意一条边
    for (i = 0; i <= N; i++) curEdge[i] = pHead[i];
    numh[0] = N;//初始全部点的层次为0
    u = pStart;//从源点开始
    //如果从源点能找到增广路
    while (h[pStart] <= N) {
        //找到增广路
        if (u == pEnd) {
            cur_flow = 1e9;
            //找到当前增广路中的最大流量, 更新断点
            for (i = pStart; i != pEnd; i = edge[curEdge[i]].v)
                if (cur_flow > edge[curEdge[i]].c) neck = i, cur_flow = edge[curEdge[i]].c;
            //增加反向边的容量
            for (i = pStart; i != pEnd; i = edge[curEdge[i]].v) {
                tmp = curEdge[i];
                edge[tmp].c -= cur_flow, edge[tmp ^ 1].c += cur_flow;
            }
            flow_ans += cur_flow;//累计流量
            u = neck;//从断点开始找新的增广路
        }
        //找到一条允许弧
        for ( i = curEdge[u]; i != 0; i = edge[i].next)
            if (edge[i].c && h[u] == h[edge[i].v] + 1)     break;
        //继续DFS
        if (i != 0) {
            curEdge[u] = i, pre[edge[i].v] = u;
            u = edge[i].v;
        }
        //当前起点没有允许弧,从u找不到增广路
        else {
            //u所在的层次点减少一,且如果没有与当前点一个层次的点, 退出.
            if (0 == --numh[h[u]]) continue;
            //有与u相同层次的点, 更新u的层次 ,回到上一个点
            curEdge[u] = pHead[u];
            for (tmp = N, i = pHead[u]; i != 0; i = edge[i].next)
                if (edge[i].c)  tmp = min (tmp, h[edge[i].v]);
            h[u] = tmp + 1;
            ++numh[h[u]];
            if (u != pStart) u = pre[u];
        }
    }
    return flow_ans;
}
inline void build() {
    char ch;
    scanf ("%d %d", &n, &m);
    ms (g, -1), ms (pHead, 0), nCnt = 1;
    for (int i = 1; i <= n; i++) {
        getchar();
        for (int j = 1; j <= m; j++) {
            ch = getchar();
            if (ch == ‘.‘)  g[i][j] = 0;
            if (ch == ‘D‘) g[i][j] = 1;
        }
    }
    n += 2, m += 2;
    SS = n * m, ST = SS + 1;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            int u = i * m + j;
            if (i == 0 || i == n - 1 || j == 0 || j == m - 1) {
                addEdge (u, ST, 4);
                continue;
            }
            if (g[i][j] == 0)  {
                for (int k = 0; k < 4; k++) {
                    int x = i + dx[k], y = j + dy[k];
                    int v = m * x + y;
                    if (g[x][y] != 1)    addEdge (u, v, 1);
                }
            }
            if (g[i][j] == 1) {
                addEdge (SS, u, 4);
                for (int k = 0; k < 4; k++) {
                    int x = i + dx[k], y = j + dy[k];
                    int v = m * x + y;
                    if (g[x][y] != 1 )     addEdge (u, v, 1);
                }
            }
        }
    }
}
int cs;
int main() {
    /*
           建图,前向星存边,表头在pHead[],边计数 nCnt.
           SS,ST分别为源点和汇点
    */
    scanf ("%d", &cs);
    while (cs--) {
        build();
        printf ("%d\n", SAP (SS, ST, n * m + 1) );
    }
    return 0;
}

时间: 2024-10-25 13:59:18

LA 6474 Drop Zone 解题报告的相关文章

LA 6476 Outpost Navigation 解题报告

题目链接 Solution DFS+剪枝 对于一个走过点k,如果有必要再走一次,那么一定是走过k后在k点的最大弹药数增加了.否则一定没有必要再走. 记录经过每个点的最大弹药数,对dfs进行剪枝. #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <map> using namespace std; map<string

解题报告 之 HDU5336 XYZ and Drops

解题报告 之 HDU5336 XYZ and Drops Description XYZ is playing an interesting game called "drops". It is played on a  grid. Each grid cell is either empty, or occupied by a waterdrop. Each waterdrop has a property "size". The waterdrop cracks

2019模拟赛09场解题报告

目录 2019模拟赛09场解题报告 目录la~~ 题一:瞬间移动 题二:食物订购 题三:马蹄印 题四:景观美化 2019模拟赛09场解题报告 标签(空格分隔): 解题报告 Forever_chen 2019.8.20 目录la~~ 题一:瞬间移动 [题面] 有一天,暮光闪闪突然对如何将一个整数序列a1,a2,...,an排序为一个不下降序列起了兴趣.身为一只年轻独角兽的她,只能进行一种叫做"单元转换"(unit shift)的操作.换句话说,她可以将序列的最后一个元素移动到它的起始位置

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

hdu 1541 Stars 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 题目意思:有 N 颗星星,每颗星星都有各自的等级.给出每颗星星的坐标(x, y),它的等级由所有比它低层(或者同层)的或者在它左手边的星星数决定.计算出每个等级(0 ~ n-1)的星星各有多少颗. 我只能说,题目换了一下就不会变通了,泪~~~~ 星星的分布是不是很像树状数组呢~~~没错,就是树状数组题来滴! 按照题目输入,当前星星与后面的星星没有关系.所以只要把 x 之前的横坐标加起来就可以了

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

[noip2011]铺地毯(carpet)解题报告

最近在写noip2011的题,备战noip,先给自己加个油! 下面是noip2011的试题和自己的解题报告,希望对大家有帮助,题目1如下 1.铺地毯(carpet.cpp/c/pas) [问题描述]为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有n 张地毯,编号从1 到n.现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上.地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的

ACdream 1203 - KIDx&#39;s Triangle(解题报告)

KIDx's Triangle Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description One day, KIDx solved a math problem for middle students in seconds! And than he created this problem. N