bzoj 1066 蜥蜴(最大流)

6 篇文章 0 订阅

题目传送门

Description

在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃
到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石
柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不
变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个
石柱上。

Input

输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱
,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。

Output

输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。

题解

这道题很明显是一道最大流问题,ans=蜥蜴数-maxflow。建图时将每根柱子当作两个点来处理,中间连接一条容量为h的边,之后建立超级源点和超级汇点,跑一个最大流就好了。
#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
 
inline int rd(){
    char c = getchar();
    while(c<'0'||c>'9')c = getchar();
    return c - '0';
}
typedef pair<int,int> pii;
char mp[25][25];
int t, r, c, hx[1000], hy[1000], totp, totE = -1;
struct edge {
    int to, next, f, c;
}E[1000000];
int head[1000];
 
inline bool in_dis(const int& dx, const int& dy) {
    return (dx * dx + dy * dy) <= t;
}
 
inline void adde(const int& a, const int& b, const int& c) {
    E[++totE].to = b; E[totE].next = head[a];
    E[totE].c = c; E[totE].f = 0;
    head[a] = totE;
}
//
const int INF = 1 << 30;
int d[1000], dt[1000], S, T, last[1000];
 
int dfs(const int& u, int flow) {
    if (u == T || !flow) return flow;
    int tmp, res = 0, v;
    for (int i = last[u]; ~i; i = E[i].next) {
        v = E[i].to; last[u] = i;
        if (d[u] > d[v] && E[i].f < E[i].c) {
            tmp = dfs(v, min(flow, E[i].c - E[i].f));
            res += tmp; flow -= tmp;
            E[i].f += tmp; E[i^1].f -= tmp; 
            if (!flow) return res;
        }
    }
    if (d[S] >= INF) return res;
    if (!(--dt[d[u]])) d[S] = INF;
    if (d[u] != INF) {
        ++d[u]; ++dt[d[u]]; last[u] = head[u];
    }
    return res;
}
 
int SAP() {
    memset(d, 0, sizeof d); memset(dt, 0, sizeof dt);
    dt[0] = totp+2; int ans = 0;
    for (int i = S; i <= T; ++i) last[i] = head[i];
    while (d[S] < INF) ans += dfs(S,INF);
    return ans;
}
 
//
#define MK make_pair
int main() {
    int d, a;
    scanf("%d%d%d", &r, &c, &d);
    t = d * d; 
    memset(head, -1, sizeof head);
    for (int i = 1; i <= r; ++i) 
        for (int j = 1; j <= c; ++j) {
            if (a = rd()) {
                hx[++totp] = i; hy[totp] = j;
                adde(totp,totp+1,a); adde(totp+1,totp,0);
                ++totp;
            }
        }
    int tot = 0; S = 0; T = totp + 1;
    for(int i = 1; i <= r; ++i)
    {
        scanf("%s",mp[i] + 1);
        for(int j = 1;j <= c; ++j) if(mp[i][j] == 'L') ++tot;
    }
     
    for(int i = 1;i <= totp;i += 2){
        for (int j = i + 2; j <= totp; j += 2)
        if (in_dis(hx[i]-hx[j],hy[i]-hy[j])) {
            adde(i + 1,j,tot),adde(j,i + 1,0);
            adde(j + 1,i,tot),adde(i,j + 1,0);
        }
        if (mp[hx[i]][hy[i]] == 'L') adde(S, i, 1), adde(i ,S, 0);
        if (hx[i] <= d || hy[i] <= d || (r - hx[i] < d) || (c - hy[i] < d) ) 
            adde(i + 1, T, tot), adde(T, i + 1, 0);
    }
    //printf("%d\n", totE);
    printf("%d", tot - SAP());
    return 0;
}

ps:我在做这道题时迷之错误。在BZOJ上超时,在codevs上RE,本机上测又对了。最后才发现是数组开小了。为什么C++没有越界的异常处理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值