好久没更博客了,最近回来刷题。今天做了一道2014年河南省选【贴海报】,用到了浮水法,写篇博客。
适用:浮水法主要使用于有覆盖的染色问题。
方法本身的思想不难理解:(以【贴海报】为背景)想象所有的海报都漂浮在水面上。如果一张海报的部分上方没有被其他海报阻挡,则上浮。
如果这部分能上浮到最高处,那么这部分就是可以被观察到的一部分。
题目
题目描述
Bytetown城市要进行市长竞选,所有的选民可以畅所欲言地对竞选市长的候选人发表言论。为了统一管理,城市委员会为选民准备了一个张贴海报的electoral墙。
张贴规则如下:
-
electoral墙是一个长度为N个单位的长方形,每个单位记为一个格子;
-
所有张贴的海报的高度必须与electoral墙的高度一致的;
-
每张海报以“A B”表示,即从第A个格子到第B个格子张贴海报;
-
后贴的海报可以覆盖前面已贴的海报或部分海报。
现在请你判断,张贴完所有海报后,在electoral墙上还可以看见多少张海报。
输入格式
第一行: N M 分别表示electoral墙的长度和海报个数
接下来M行: Ai Bi 表示每张海报张贴的位置
输出格式
输出贴完所有海报后,在electoral墙上还可以看见的海报数。
输入输出样例
输入 #1
100 5 1 4 2 6 8 10 3 4 7 10
输出 #1
4
【约束条件】
1 0<= N <= 10000000 1<=M<=1000 1<= Ai <= Bi <=10000000
所有的数据都是整数。数据之间有一个空格
分析
很显然,这道题目中有覆盖的问题,那么我们可以用到浮水法来处理。解具体的题目有几个注意的地方,结合代码来看。
- 读入时,每个右端点加上1。因为这个端点也覆盖了海报。
- 倒序处理(j 从大到小)。这是显然的,因为题目存在覆盖的顺序,从上到下处理。
- 题目的提示中指出,相同的海报分两处被看见算一张海报,所以我们引入一个vis数组,来表示该海报是否已经被算入ans答案中。
- while 和 if 中是否取等号有明显区别,留给读者自行画图思考。
程序
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN = 10000000 + 10, MAXM = 1000 + 10; 4 int n, m, ans = 0, j, A[MAXM], B[MAXM]; 5 bool vis[MAXM]; 6 void work(int a, int b, int l) 7 { 8 if (vis[j]) 9 return; 10 while (l <= m && (a >= B[l] || b <= A[l])) 11 ++l; 12 if (l > m) 13 ans++, vis[j] = true; 14 if (a < A[l] && A[l] < b) 15 work(a, A[l], l+1); 16 if (b > B[l] && B[l] > a) 17 work(B[l], b, l+1); 18 } 19 int main() 20 { 21 cin >> n >> m; 22 for (int i = 1; i <= m; i++) 23 { 24 cin >> A[i] >> B[i]; 25 ++B[i]; 26 } 27 for (j = m - 1; j >= 1; j--) 28 work(A[j], B[j], j+1); 29 cout << ans+1 << endl; 30 return 0; 31 }