横截面图
Time Limit : 1 sec Memory Limit : 131072 KB
Description
你的任务是模拟洪水灾害。 对于给定的横截面图,报告淹没区域的横截面积。
假设该地区持续降雨,从该地区溢出的多余雨水将流入两侧的海水中。例如,对于上面的横截面图,降雨将引发洪水,积水处的横截面积从左至右分别为4、2、1、19和9。
Input
一个字符串,分别用' / ',' '和' _ ' 表示斜坡和平地,用一行表示。例如,上面示例的区域由字符串“ \ /// _ / / \\ / _ / \ /// __ \ _ \ / _ / _ / “表示。
output
第一行输出该区域积水处的横截总面积A(整数)。 第二行从左至右按顺序输出积水处的数量k,以及各积水处的横截面积 Li(i=1,2,...,k)。
Constraints
1 ≤ 字符串长度 ≤ 20000
Sample Input 1
\//
Sample Output 1
4
1 4
Sample Input 2
\///\_//\\/_/\///__\\_\/_/_/
Sample Output 2
35
5 4 2 1 19 9
分析:
由淹没区域可以想到 ‘’ 与 '/' 的配对。
此题比较特别的是如何组成一整个被水淹没的区间?答案是将所有配对的区间中 相互包含的区间合并。
如何合并呢?可以知道大区间所包含的小区间必定比大区间先入栈,则可以依此合并。
如何计算横截面积?所有配对的‘’与'/'之间形成的横截面都为梯形或三角形,把问题分解为多个小问题来解答。
放代码:
#include<cstdio> #include<cstring> #include<iostream> #include<stack> using namespace std; struct area { int begin,end; bool fl; }; int main() { freopen("areas.in","r",stdin); freopen("areas.out","w",stdout); stack <int> stack; area k[20050]; for(int i = 0;i<= 20000;i++) k[i].fl = 0; int order,ans[20050]; memset(ans,0,sizeof(ans)); string s; cin>>s; int top = -1,j; bool rise = 1; for(int i = 0; i < s.size(); i++) { if(s[i] == '\')stack.push(i); if(s[i] == '/' && !stack.empty()) { order = stack.top(); stack.pop(); k[++top].begin = order; k[top].end = i; } } int i = top,x,y; while(i >= 0) { j = i; x = k[i].begin, y = k[i].end; k[i].fl = 1; while(k[i].begin >= x && k[i].end <= y) { ans[j] += k[i].end-k[i].begin; i--; if(i < 0)break; } } long long int anssum = 0,num=0; for(int i=0;i<=top;i++) { if(k[i].fl) anssum += ans[i],num++; } cout<<anssum<<endl<<num<<' '; for(int i=0;i<=top;i++) { if(k[i].fl) cout<<ans[i]<<' '; } fclose(stdin); fclose(stdout); return 0; }