[BZOJ 1066] [SCOI2007] 蜥蜴 【最大流】

题目链接:BZOJ - 1066

题目分析

题目限制了高度为 x 的石柱最多可以有 x 只蜥蜴从上面跳起,那么就可以用网络流中的边的容量来限制。我们把每个石柱看作一个点,每个点拆成 i1, i2,从 i1 到 i2 连一条边,容量为这个石柱 i 的高度,即跳跃次数限制。来到这个石柱就是向 i1 连边,从这个石柱跳起就是从 i2 向外连边,这样只要从石柱 i 跳起就一定会消耗 i1 到 i2 的边的容量。如果 i 有蜥蜴,就从 S 到 i1 连一条容量为 1 的边,如果从石柱 i 能跳出边界,就从 i2 到 T 连 INF 的边。如果从石柱 i 能跳到石柱 j ,就从 i2 到 j1 连 INF 的边。这样求出的最大流就是能够跳出的蜥蜴的数量。

题目还限制了“任何时刻不能有两只蜥蜴在同一个石柱上”,但是想一想就会发现,这个限制其实并没有影响,只要我们按照合适的顺序让蜥蜴们先后跳跃,就一样可以让那些应该跳出的蜥蜴跳出。

另外,题目要求输出不能跳出的蜥蜴的数量,结果我直接输出了能跳出的数量...于是对着数据调了1h...最后发现是输出的东西不对...QAQ

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
 
using namespace std;
 
const int MaxR = 20 + 5, MaxN = 400 * 2 + 5, MaxM = 500000 * 2 + 5, INF = 0x3fffffff;
 
int n, m, Dis, Top, S, T, Tot, Ans, Sum;
int Num[MaxN], d[MaxN];
 
bool Be[MaxR][MaxR];
 
char Str[MaxR];
 
struct Edge
{
    int v, w;
    Edge *Next, *Other;
} E[MaxM], *P = E, *Point[MaxN], *Last[MaxN];
 
inline void AddEdge(int x, int y, int z) {
    Edge *Q = ++P; ++P;
    P -> v = y; P -> w = z;
    P -> Next = Point[x]; Point[x] = P; P -> Other = Q;
    Q -> v = x; Q -> w = 0;
    Q -> Next = Point[y]; Point[y] = Q; Q -> Other = P;
}
 
struct ES
{
    int x, y, z;
    ES() {}
    ES(int a, int b, int c) {
        x = a; y = b; z = c;
    }
} JF[MaxN];
 
typedef double DB;
 
bool Check(int x, int y) {
    if ((x - 1) < Dis || (y - 1) < Dis) return true;
    if ((n - x) < Dis || (m - y) < Dis) return true;
    return false;
}
 
inline DB Sqr(DB x) {return x * x;}
 
DB Calc(DB x, DB y, DB xx, DB yy) {
    return sqrt(Sqr(x - xx) + Sqr(y - yy));
}
 
inline int gmin(int a, int b) {return a < b ? a : b;}
 
int DFS(int Now, int Flow) {
    if (Now == T) return Flow;
    int ret = 0;
    for (Edge *j = Last[Now]; j; j = j -> Next) {
        if (j -> w && d[Now] == d[j -> v] + 1) {
            Last[Now] = j;
            int p = DFS(j -> v, gmin(j -> w, Flow - ret));
            j -> w -= p; j -> Other -> w += p; ret += p;
            if (ret == Flow) return ret;
        }
    }
    if (d[S] >= Tot) return ret;
    if (--Num[d[Now]] == 0) d[S] = Tot;
    ++Num[++d[Now]];
    Last[Now] = Point[Now];
    return ret;
}
 
int main()
{
    scanf("%d%d%d", &n, &m, &Dis);
    Top = 0;
    for (int i = 1; i <= n; ++i) {
        scanf("%s", Str);
        for (int j = 1; j <= m; ++j) {
            if (Str[j - 1] != ‘0‘) {
                JF[++Top] = ES(i, j, Str[j - 1] - ‘0‘);
            }
        }  
    }
    Sum = 0;
    for (int i = 1; i <= n; ++i) {
        scanf("%s", Str);
        for (int j = 1; j <= m; ++j) {
            if (Str[j - 1] == ‘L‘) {
                Be[i][j] = true;
                ++Sum;
            }
            else Be[i][j] = false;
        }
    }
    S = Top * 2 + 1; T = S + 1; Tot = T;
    for (int i = 1; i <= Top; ++i) {
        int xx = JF[i].x, yy = JF[i].y;
        AddEdge(i, Top + i, JF[i].z);
        if (Check(xx, yy)) AddEdge(Top + i, T, INF);
        if (Be[xx][yy]) AddEdge(S, i, 1);
        for (int j = 1; j <= Top; ++j) {
            if (j == i) continue;
            if (Calc(xx, yy, JF[j].x, JF[j].y) <= (DB)Dis)
                AddEdge(Top + i, j, INF);
        }
    }
    for (int i = 1; i <= Tot; ++i) Last[i] = Point[i];
    memset(Num, 0, sizeof(Num)); Num[0] = Tot;
    memset(d, 0, sizeof(d));
    Ans = 0;
    while (d[S] < Tot) Ans += DFS(S, INF);
    printf("%d\n", Sum - Ans);
    return 0;
}

  

时间: 2024-08-01 10:44:35

[BZOJ 1066] [SCOI2007] 蜥蜴 【最大流】的相关文章

BZOJ 1066: [SCOI2007]蜥蜴( 最大流 )

结点容量..拆点然后随便写 --------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define chk(x, y) (x >= 0 && x < R && y >= 0 && y

BZOJ 1066 [SCOI2007]蜥蜴(最大流)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1066 [题目大意] 在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴, 你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为1, 蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上. 石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1 (如果仍然落在地图内部,则到达的石柱高度不变), 如果该石柱原来高度为1,则蜥蜴离开后消失.以后其

bzoj 1066 : [SCOI2007]蜥蜴 网络流

题目链接 给一个n*m的图, 里面每一个点代表一个石柱, 石柱有一个高度. 初始时有些石柱上面有蜥蜴, 蜥蜴可以跳到距离他曼哈顿距离小于等于d的任意一个石柱上,跳完后, 他原来所在的石柱高度会减一, 如果高度变为0, 那么石柱消失, 无法在跳到这个位置上, 跳到的那个石柱高度不会发生改变, 同一时刻一个石柱无法站两个蜥蜴.问有多少蜥蜴无法跳出边界. 很裸的网络流, 如果一个石柱距离边界距离小于d, 那么向汇点连一条权值为inf的边, 如果一个石柱初始有蜥蜴, 那么源点向这个点连一条1的边, 每个

[BZOJ 1066][SCOI2007]蜥蜴(网络流)

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

bzoj 1066: [SCOI2007]蜥蜴

1 #include<cstdio> 2 #include<iostream> 3 #define T 1001 4 #define M 10005 5 #define inf 0x7fffffff 6 #include<cstring> 7 using namespace std; 8 int cnt=1,r,c,d,head[M],next[10*M],u[10*M],v[10*M],sum,f[25][25],d1[M],q[M],ans; 9 char ch[5

[SCOI2007] 蜥蜴 (最大流)

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

【BZOJ】1066: [SCOI2007]蜥蜴(最大流)

本题想一想应该懂了的. 我们想啊,,每个点都有限制,每个点都可以跳到另一个有限制的点,每个有蜥蜴的点都可以跳到四周的有限制的点,,哈哈,自然会想到网络流. 其中很自然的可以相到,要表示每个点的容量限制,那么就拆点,一个上,一个下,容量为权值 然后向四周连接也就是某个点的下将距离范围内的某个点的上连接,容量为oo 源向蜥蜴连接,容量为1 可以跑到边界外的点的下向汇连接,容量为oo 跑一次最大流,答案就是蜥蜴总数减去最大流. #include <cstdio> #include <cstri

【bzoj】 1066: [SCOI2007]蜥蜴 (网络流)

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

bzoj 1070: [SCOI2007]修车 -- 费用流

1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 128 MB Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小. 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间. Input 第一行有两个m,n,表示技术人员数与顾客数. 接下来n行,每行m个整数.第