[POI2007]洪水pow

Description
AKD市处在一个四面环山的谷地里。最近一场大暴雨引发了洪水,AKD市全被水淹没了。Blue Mary,AKD市的市长,召集了他的所有顾问(包括你)参加一个紧急会议。经过细致的商议之后,会议决定,调集若干巨型抽水机,将它们放在某些被水淹的区域,而后抽干洪水。你手头有一张AKD市的地图。这张地图是边长为\(m\times n\)的矩形,被划分为\(m\times n\)\(1\times 1\)的小正方形。对于每个小正方形,地图上已经标注了它的海拔高度以及它是否是AKD市的一个组成部分。地图上的所有部分都被水淹没了。并且,由于这张地图描绘的地面周围都被高山所环绕,洪水不可能自动向外排出。显然,我们没有必要抽干那些非AKD市的区域。每个巨型抽水机可以被放在任何一个\(1\times 1\)正方形上。这些巨型抽水机将持续地抽水直到这个正方形区域里的水被彻底抽干为止。当然,由连通器原理,所有能向这个格子溢水的格子要么被抽干,要么水位被降低。每个格子能够向相邻的格子溢水,“相邻的”是指(在同一高度水平面上的射影)有公共边。

Input
第一行是两个数m,n(1<=m,n<=1000). 以下m行,每行n个数,其绝对值表示相应格子的海拔高度;若该数为正,表示他是AKD市的一个区域;否则就不是。请大家注意:所有格子的海拔高度其绝对值不超过1000,且可以为零.

Output
只有一行,包含一个整数,表示至少需要放置的巨型抽水机数目。

Sample Input
6 9
-2 -2 -1 -1 -2 -2 -2 -12 -3
-2 1 -1 2 -8 -12 2 -12 -12
-5 3 1 1 -12 4 -6 2 -2
-5 -2 -2 2 -12 -3 4 -3 -1
-5 -6 -2 2 -12 5 6 2 -1
-4 -8 -8 -10 -12 -8 -6 -6 -4

Sample Output
2

HINT

首先我说一下题意:
1、所谓溢水就是你想的那么简单,只能向四周溢水,并且满足物理定理
2、开始的时候洪水要多高有多高
3、HINT里面灰色的是城市,不是说抽水机能抽走哪些格子里的水

抽水机放在城市里一定是最优的,而且抽水机一定要从高度低的地方放起。如果说一个点上放了抽水机,那么它周围点的上面都要放一个抽水机,记得都要放一个抽水机,但是不一定是挨着地面放的。那些被间接放了抽水机的点我们称其为伪抽水机。

然后我们从最低的点开始枚举,如果有伪抽水机的话先对其进行拓展,如果不能拓展了就找到那些没有被抽水的城市开始抽水。

然后记得无论如何都是从最低的点开始拓展,排序的话就开个vector来维护。

/*program from Wolfycz*/
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+'0');
}
const int N=1e3;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
struct ID{int x,y;};
vector<ID> h1[N+10],h2[N+10];
int v[N+10][N+10],map[N+10][N+10];
int n,m,Ans,Max;
bool in_map(int x,int y){return x>0&&x<=n&&y>0&&y<=m;}
void bfs(int x,int y){
    for (int k=0;k<4;k++){
        int tx=x+dx[k],ty=y+dy[k];
        if (!in_map(tx,ty)||~v[tx][ty]) continue;
        v[tx][ty]=max(v[x][y],map[tx][ty]);
        h2[v[tx][ty]].push_back((ID){tx,ty});
    }
}
int main(){
    n=read(),m=read();
    memset(v,255,sizeof(v));
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            int x=read();
            Max=max(Max,x);
            if (x>0)    h1[x].push_back((ID){i,j});
            map[i][j]=abs(x);
        }
    }
    for (int i=1;i<=Max;i++){//按高度来拓展
        while (true){
            if (h2[i].size()){
                int x=h2[i].back().x,y=h2[i].back().y;
                h2[i].pop_back();
                bfs(x,y);
            }else   if (h1[i].size()){
                int x=h1[i].back().x,y=h1[i].back().y;
                h1[i].pop_back();
                if (~v[x][y])   continue;//因为是从低到高来拓展,所以如果被标记了就一定被抽光了
                Ans++;
                v[x][y]=map[x][y];
                bfs(x,y);
            }else   break;
        }
    }
    printf("%d\n",Ans);
    return 0;
}   

猜你喜欢

转载自www.cnblogs.com/Wolfycz/p/8934002.html