[POI2007]洪水pow

问题 E: [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

样例输出

2solution:    数据很水,一开始没理解题意瞎打了个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 }

 
时间: 2024-10-07 04:06:21

[POI2007]洪水pow的相关文章

[POI2007]洪水pow 题解

[POI2007]洪水pow 时间限制: 5 Sec  内存限制: 128 MB 题目描述 AKD市处在一个四面环山的谷地里.最近一场大暴雨引发了洪水,AKD市全被水淹没了.Blue Mary,AKD市的市长,召集了他的所有顾问(包括你)参加一个紧急会议.经过细致的商议之后,会议决定,调集若干巨型抽水机,将它们放在某些被水淹的区域,而后抽干洪水.你手头有一张AKD市的地图.这张地图是边长为m*n的矩形,被划分为m*n个1*1的小正方形.对于每个小正方形,地图上已经标注了它的海拔高度以及它是否是A

[POI2007]洪水pow 并查集

我们先得出一个结论:水泵要建在城市上.因为如果在非城市上建能把其他一些城市抽干,那么在城市上建也是一个效果(自己画图感性理解一下) 然后我们明白抽水的条件:周围的高度要>=自身的高度,这样会抽完它.如果低的话,会降低旁边位置的水位(这很重要) 然后我们枚举每一个城市,看它用不用建造.这样在每一个城市,枚举所有位置,看这个位置能不能被四周的抽干,这样用并查集维护,能抽干的都是一个祖先 这样枚举完一遍后,看这个城市所连的并查集有没有被抽干,如果没有,就在那里建造即可 #include<iostre

BZOJ1104 : [POI2007]洪水pow

从小到大枚举高度i: 对于所有高度为i的点x,将它与它四周相邻的高度不超过i的点所在的集合合并 对于所有高度为i的城市x,如果它所在集合没有放置水泵,则需要放置 并查集维护,时间复杂度$O(nm)$. #include<cstdio> #define N 1010 int n,m,i,j,k,x,y,a[N][N],id[N][N],f[N*N],v[N*N],cnt,dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},ans; struct E{int x,y;E*nxt;}

BZOJ 1104 POI2007 洪水pow 并查集

题目大意:给定一张地势图,所有的点都被水淹没,现在有一些关键点,要求放最少的水泵使所有关键点的水都被抽干 前排感谢VFK 首先可以证明一定存在一种最优解使所有的水泵都在关键点上 那么我们将所有关键点按照高度排序,从小到大枚举每个关键点 对于每个关键点x,我们将所有高度小于等于x点的点都加入并查集并将相邻的合并 由于x是并查集中最高的点,因此并查集中任意一个点放置水泵都会导致点x被抽干 故如果x所在并查集中已经放置过水泵,则无需在x点放置水泵 否则就要在x点放置一个水泵 时间复杂度O(mnlog(

洪水 Pow

Description AKD市处在一个四面环山的谷地里.最近一场大暴雨引发了洪水,AKD市全被水淹没了.Blue Mary,AKD市的市长,召集了他的所有顾问(包括你)参加一个紧急会议.经过细致的商议之后,会议决定,调集若干巨型抽水机,将它们放在某些被水淹的区域,而后抽干洪水. 你手头有一张AKD市的地图.这张地图是边长为m*n的矩形,被划分为m*n个1*1的小正方形.对于每个小正方形,地图上已经标注了它的海拔高度以及它是否是AKD市的一个组成部分.地图上的所有部分都被水淹没了.并且,由于这张

联赛之前的题表(已完成)汇总(可能有遗漏)

联赛之前的搞搞(其实是懒得分类) 博弈论 poj3537 poj1704 hdu5996两个插头 HDU1693 Eat the Trees COGS1283. [HNOI2004] 邮递员kdtree板子1941: [Sdoi2010]Hide and Seek旋转卡壳 pj2187凸包 cogs896 bzoj2829 信用卡凸包莫比乌斯反演基础 bzoj 4173 zhao gui lv bzoj 3529 mobiwus bzoj 4407 mobiwus bzoj 2818 mobiw

LeetCode 50 Pow(x, n)(Math、Binary Search)(*)

翻译 实现pow(x, n). 原文 Implement pow(x, n). 分析 首先给大家推荐维基百科: zh.wikipedia.org/wiki/二元搜尋樹 en.wikipedia.org/wiki/Binary_search_tree 其次,大家也可以看看类似的一道题: LeetCode 69 Sqrt(x)(Math.Binary Search)(*) 然而这题我还是没有解出来,看看别人的解法-- class Solution { private: double myPowHel

Pow(x, n)

Implement pow(x, n). class Solution { public: double myPow(double x, int n) { // Start typing your C/C++ solution below // DO NOT write int main() function if(n<0) { if(n==INT_MIN) return 1.0 / (myPow(x,INT_MAX)*x); else return 1.0 / myPow(x,-n); } i

【BZOJ 1103】 [POI2007]大都市meg

1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1292  Solved: 660 [Submit][Status] Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了.不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1..n的n个小村庄,某些村庄之间有一些双向的土路.从每个村庄都恰好有一条路径到达村庄1(即比特