• 【模拟赛·岛屿】


    【问题描述】

    从前有一座岛屿,这座岛屿是一个长方形,被划为 N*M 的方格区域,每个区域都有一个确定的高度。不幸的是海平面开始上涨,在第 i 年,海平面的高度为 t[i]。如果一个区域的高度小于等于海平面高度,则视为被淹没。那些没有被淹没的连通的区域够成一个连通块。现在问第 i 年,这样的连通块有多少个。例如:第一年海平面高度为 1,有 2 个连通块。第二年海平面高度为 2,有 3 个连通块。

    【输入】

    第一行包含两个数 N,M。接下来是一个 N*M 的矩阵,第 i 行第 j 列表示这个格子的高度 h[i][j] 接下来是一个数 T,表示有 T 天,最后一行有 T 个数,第 i 个数表示第 i 天的水位高度。(保证是递增的)

    【输出】

    输出包含一行 T 个数,第 i 个数表示第 i 天的连通块个数。

    【输入输出样例】

    island.in

    island.out

    4 5 1 2 3 3 1 1 3 2 2 1 2 1 3 4 3 1 2 2 2 2 5 1 2 3 4 5 2 3 1 0 0

    【数据范围】

    对于 50%的数据:1 <= n*m <= 1000, 1<= T <=3000

    对于 100%的数据:1<= n <= 3000 , 1<= m <= 3000 , 1<=T<=100000 1<= h[i][j] <=10^9

    【题解】

          ①正难则反。

          ②加入当前高于水位的块,使用并查集维护连通块去重即可。

          ③试试FREAD读入优化吧。

    #include<stdio.h>
    #include<algorithm>
    #define OUT(i,j) (i<1||i>n||j<1||j>m)
    #define go(i,a,b) for(int i=a;i<=b;i++)
    #define ro(i,a,b) for(int i=a;i>=b;i--)
    const int N=3005;bool dry[N*N];
    struct info{int x,y,h;}a[N*N];
    int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    int n,m,s,H,fa[N*N],T,t[N*N],ans[N*N],now; 
    int ID(int x,int y){return (x-1)*m+y;}
    bool cmp(info A,info B){return A.h<B.h;}
    int Find(int u){return u==fa[u]?u:fa[u]=Find(fa[u]);}
    
    char Getchar()
    {
    	static char C[1000000],*p1,*p2;
    	if(p1==p2)p2=(p1=C)+fread(C,1,1000000,stdin);
    	if(p1==p2)return EOF;return *p1++;
    }
    
    void read(int &x)
    {
    	x=0;char c=Getchar();
    	while(c<'0'||c>'9')c=Getchar();
    	while(c>='0'&&c<='9')x=x*10+c-'0',c=Getchar();
    }
    
    int main()
    {
    	freopen("island.in","r",stdin);
    	freopen("island.out","w",stdout);
    	
    	read(n);read(m);
    	go(i,1,n)go(j,1,m)read(H),a[++s]=(info){i,j,H},fa[s]=s;
    	read(T);go(i,1,T)read(t[i]);std::sort(a+1,a+s+1,cmp);
    	ro(i,T,1){while(s&&a[s].h>t[i])
    	{
    		now++;dry[ID(a[s].x,a[s].y)]=1;go(k,0,3)
    		{
    			if(OUT(a[s].x+dx[k],a[s].y+dy[k]))continue;
    			int u=ID(a[s].x,a[s].y),v=ID(a[s].x+dx[k],a[s].y+dy[k]);
    			if(!dry[v])continue;int U=Find(u),V=Find(v);
    			if(U==V)continue;fa[V]=U;now--;
    		}s--;
    	}
    	ans[i]=now;}go(i,1,T)printf("%d ",ans[i]);return 0;
    }//Paul_Guderian
    

    .

  • 相关阅读:
    C#设置窗体最大化且不遮挡任务栏的方法
    C# Base64解码 二进制输出
    导出Excel并下载,但无法定制样式的方法!
    C# List 转Datatable
    查询sql语句耗时的方法!
    301跳转
    文章关键字加链接
    文本框样式默认文本
    JForum二次开发(一)
    MongoDB 学习笔记(三)—— 修改器的使用
  • 原文地址:https://www.cnblogs.com/Damitu/p/7793302.html
Copyright © 2020-2023  润新知