[POI2007]洪水pow

[POI2007]洪水pow

时间限制: 5 Sec  内存限制: 128 MB

题目描述

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

输入

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

输出

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

样例输入

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
 

样例输出

2
solution:
    数据很水,一开始没理解题意瞎打了个bfs过了4个点,正解应该是并查集,对于一个海拔为x的点,如果与它相邻的点中有一个海拔小于等于x的点能被抽干,那么它也可以一同被抽干;把所有点关于海拔排序,那么依次加入高度为h的点后去判断一下有没有与已经放了抽水机的点相连,如果没有则答案+1,并且在该点放上一个抽水机。
    当然bfs也可以,但本蒟蒻被bfs干怕了,死活调不过去,于是就打了并查集,大佬们可以试试bfs。
 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<queue>
 6 using namespace std;
 7 #define inf 0x3f3f3f3f
 8 #define maxn 1005
 9 int read() {
10     int s=0,f=1;
11     char ch=getchar();
12     while(ch>'9'||ch<'0') {
13         if(ch=='-') {
14             f=-1;
15         }
16         ch=getchar();
17     }
18     while(ch>='0'&&ch<='9') {
19         s=(s<<1)+(s<<3)+(ch^48);
20         ch=getchar();
21     }
22     return s*f;
23 }
24 int n,m,h[maxn][maxn],fa[maxn*maxn],cnt,ans,mv[4][2]= {1,0,-1,0,0,1,0,-1},empty[maxn*maxn];
25 int num[maxn][maxn],tot;
26 struct oo {
27     int x,y,hei;
28     friend bool operator < (oo a,oo b) {
29         return a.hei<b.hei;
30     }
31 } s[maxn*maxn],l[maxn*maxn];
32 inline int find(int x) {
33     return fa[x]==x?x:fa[x]=find(fa[x]);
34 }
35 void init() {
36     for(int i=0; i<=n+1; ++i)
37         h[i][0]=h[i][m+1]=inf;
38     for(int i=0; i<=m+1; ++i)
39         h[0][i]=h[n+1][i]=inf;
40     for(int i=1; i<=n*m; ++i) {
41         fa[i]=i;
42     }
43     for(int i=1; i<=n; ++i) {
44         for(int j=1; j<=m; ++j) {
45             num[i][j]=++tot;
46         }
47     }
48 }
49 int main() {
50     n=read(),m=read();
51     init();
52     memset(empty,0,sizeof(empty));
53     for(int i=1; i<=n; ++i) {
54         for(int j=1; j<=m; j++) {
55             h[i][j]=read();
56             if(h[i][j]>0) {
57                 s[++cnt].x=i,s[cnt].y=j,s[cnt].hei=h[i][j];
58             } else {
59                 h[i][j]=-h[i][j];
60             }
61             l[num[i][j]].x=i,l[num[i][j]].y=j,l[num[i][j]].hei=h[i][j];
62         }
63     }
64     sort(l+1,l+m*n+1);
65     sort(s+1,s+cnt+1);
66     ans=0;
67     for(int i=1,k=1; i<=cnt; ++i) {
68         for(; k<=m*n&&l[k].hei<=s[i].hei; ++k) {
69             int x=l[k].x,y=l[k].y;
70             for(int j=0; j<=3; j++) {
71                 int xx=x+mv[j][0],yy=y+mv[j][1];
72                 if(h[xx][yy]<=h[x][y]) {
73                     empty[find(num[x][y])]|=empty[find(num[xx][yy])];
74                     fa[find(num[xx][yy])]=find(num[x][y]);
75                 }
76             }
77         }
78         if(!empty[find((s[i].x-1)*m+s[i].y)]) {
79             ++ans;
80             empty[find((s[i].x-1)*m+s[i].y)]=1;
81         }
82     }
83     printf("%d\n",ans);
84     return 0;
85 }
 
 

 

 

转载于:https://www.cnblogs.com/forevergoodboy/p/7352915.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值