51nod 1276 岛屿的数量 思维题,很棒的题目

来源:互联网 发布:centos 桥接网络 编辑:程序博客网 时间:2024/05/16 18:57

传送门:51nod 1276


题目大意:由于是中文题就不再描述了。


Input示例
5 4213230132
Output示例
1202

思路:第一思路肯定是暴力的方法,每次询问都去查询被淹没的岛屿和不相连的岛屿数,这样的时间复杂度是O(n)*O(q),会超时。网上的思路一般都是离线处理,也就是说针对每个询问不立刻给出答案,而是等询问全部给出后一起给出答案。由于水会先淹没高度低的岛屿,所以如果先处理高度低的岛屿再处理高度高的就避免了重复计算,大大的降低了时间复杂度。

经过观察我们发现,只有淹没的岛屿为山峰(比两边都高)的时候,原来的岛屿数要-1,如果淹没的是山谷(比两边都低),一个岛变成两个,则原来的岛屿数+1. 这里要注意首尾两个岛屿比较特殊,如果它们是孤立的岛屿的话,淹没它们则岛屿数+1,否则不变化。

这样一来,我们找到了方法也找到了规律。不过还有几个难点:

1.既然要对岛屿和询问从低到高处理,那么就要对其排序,怎么确定在原数组中的位置呢?很简单,用结构体记录位置就可以了。

2.怎么判断为山峰还是山谷,我们注意到可能存在这样的数据:1 6 6 6 1,如果单纯的判断是否比两边高或比两边低是不行的。这里就有一个很巧妙的方法:当该岛屿要被淹没时,如果两边的岛屿都没被淹没,则为山谷;如果两边的岛屿都被淹没,则为山峰。


#include<stdio.h>#include<string.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;struct node{int val,pos; //记录值和位置 } a[50010],q[50010];int cmp(node x,node y){return x.val<y.val;}int main(){ //f为0表示未被淹没,为1表示已被淹没 int i,j,n,m,sum,f[50010],ans[50010];while(~scanf("%d%d",&n,&m)){for(i=0;i<n;i++){scanf("%d",&a[i].val);a[i].pos=i;}sort(a,a+n,cmp);for(i=0;i<m;i++){scanf("%d",&q[i].val);q[i].pos=i;}sort(q,q+m,cmp);j=0;sum=1; //sum记录岛屿数,初始时只有一个岛屿 memset(f,0,sizeof(f));for(i=0;i<m;i++){ //针对从小到大的每个询问 while(a[j].val<=q[i].val&&j<n){ //扫描当前水平面可以淹没的岛屿 if(a[j].pos==0){ //如果是第一个岛 if(f[a[j].pos+1]==1) sum--;}else if(a[j].pos==n-1){ //如果是最后一个岛 if(f[a[j].pos-1]==1) sum--;}else {if(f[a[j].pos+1]&&f[a[j].pos-1]) sum--; //如果两边都被淹没,则为山峰 else if(!f[a[j].pos+1]&&!f[a[j].pos-1]) sum++; //如果两边都未被淹没,则为山谷 }f[a[j].pos]=1; //当前岛屿淹没 j++;}ans[q[i].pos]=sum; //记录答案 }for(i=0;i<m;i++) printf("%d\n",ans[i]);}return 0;}

原创粉丝点击