CSP邻域均值(Java)

本文介绍了一种算法竞赛题目中的优化方案,通过减少重复计算提高效率。利用“毛毛虫”算法,将计算区域视为固定的框,使计算量大幅降低。文章详细展示了优化后的算法实现过程,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先常规解法就是暴力,遍历每个点,然后算周围一圈,这样可以拿下70分,这里我就不细说暴力了,我主要说说说如何优化的问题。

当你暴力时你就会发现每个元素会重复计算多次,我们的目标就减少这种重复的计算。之前的暴力就好比你每次给数据按上一个框进行分别计算,现在我们想的是把框固定下来,就像一个毛毛虫一样前面吃一列后面出一列,这样每个点的计算量就变成了4r+2,这样一列一列的向前推动。
还有一点小技巧就是数组的起点我设的是【100】【100】总大小是【800】【800】然后初始化的时候没用的地方用T值填充,这样就不用考虑边界问题了。
下面就是具体的代码


import java.io.*;
import java.util.*;


public class Main {

    public static void main(String[] args) throws IOException {
        //Scanner in =new Scanner(System.in);
        read in =new read();
        PrintWriter pw =new PrintWriter(System.out);
        int n=in.nextInt();
        int l=in.nextInt();
        int r=in.nextInt();
        int t=in.nextInt();
        int arr[][]=new int[800][800];
        //这部分就是初始化
        for (int i=0;i<800;i++){
            for (int j=0;j<800;j++){
                //这个判断是用来判断没用的部分,然后用t填充,这样以后计算就不会产生影响
                if (i<100||j<100||i>=100+n||j>=100+n)
                    arr[i][j]=t;
                else
                    arr[i][j]=in.nextInt();
            }
        }
        //用来记录这个框中总和的最小值,小于等于count的就是暗点
        int count=(2*r+1)*(2*r+1)*t;
        int[][] map=new int[n][n];//用来记录每个门框的大小方便推到
        int sum=0;
        int ru=0;//用来记录最后答案个数
        //这里是先算个头map【0】【0】
        for (int i=100-r;i<=100+r;i++){
            for (int j=100-r;j<=100+r;j++){
                sum+=arr[i][j];
            }
        }
        map[0][0]=sum;
        if (sum<=count)ru++;
        //这是根据00,推导map的第一行,a是记录新增的一列,b是去掉的一列
        for (int j=101;j<100+n;j++){
            int a = 0,b=0;
            for (int i=100-r;i<=100+r;i++)
                a+=arr[i][j+r];
            for (int i=100-r;i<=100+r;i++)
                b+=arr[i][j-r-1];
            map[0][j-100]=map[0][j-101]+a-b;
            if (map[0][j-100]<=count)ru++;
        }

        //上面一步已经把每列都开了一个头,这样我们就可以全部推导了,一列一列竖着来,从上往下
        for (int j=100;j<100+n;j++){
            for (int i=101;i<100+n;i++){
                int a=0,b=0;
                for (int jj=j-r;jj<=j+r;jj++){
                    a+=arr[i+r][jj];
                }
                for (int jj=j-r;jj<=j+r;jj++){
                    b+=arr[i-r-1][jj];
                }
                map[i-100][j-100]=map[i-101][j-100]+a-b;
                if (map[i-100][j-100]<=count)ru++;
            }

        }
        pw.println(ru);

        pw.flush();
        
        //这个关键就是把握每次遍历的边界,建议动手画画不容易乱,然后还不懂可以Debug一下观察一下map数组的运算过程
        //如果谁有更好的办法请不吝赐教。


    }
}
//大输入输出都要用,懂得都懂
class read{
    StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    int nextInt() throws IOException {
        st.nextToken();
        return (int)st.nval;
    }
    long nextLong() throws IOException {
        st.nextToken();
        return (long)st.nval;
    }

    String next() throws IOException {

        st.nextToken();
        return st.sval;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值