BOJ::1184 귀농

시사점

이해(x)

설계, 손 코딩(x)

naive of naive

img1

최적화 1

img2

최적화 2

img3

시간 복잡도

공간 복잡도

손 코딩 후 문제 리뷰(x)

구현(x)

함수 List

// psum을 미리 구합니다.
void precalc();

// 꼭짓점이 (x,y)이고, 반대편이 (nx, ny)인 사각형의 합을 반환합니다.
int rectSum(int nx, int ny, int x, int y);

// 그림(a)에 표현된 사각형 2개의 포지션입니다.
void LeftUp_RightDown(int x, int y);

// 그림(b)에 표현된 사각형 2개의 포지션입니다.
void LeftDown_RightUp(int x, int y);

업데이트 되는 변수

// 업데이트 되는 변수 -------------------------------------------------------
int psum[MAXN][MAXN]; // psum[i][j] : (1,1)부터 (i,j)까지의 사각형의 합
map<int, int> mp;  // 사각형의 합을 처리할때 사용하는 map
// 업데이트 되는 변수 -------------------------------------------------------

실제 구현

#include<iostream>
#include<map>
#define rep(i, a, b) for(int i=a;i<b;i++)
const int MAXN = 50 + 2;
using namespace std;

int n, ans;
int a[MAXN][MAXN];
int psum[MAXN][MAXN]; //  // psum[i][j] : (1,1)부터 (i,j)까지의 사각형의 합
map<int, int> mp; // 사각형의 합을 처리할때 사용하는 map

// psum을 미리 구합니다.
void precalc(){
    psum[1][1] = a[1][1];
    rep(i, 1, n + 1) rep(j, 1, n + 1)
    psum[i][j] = psum[i - 1][j] + psum[i][j - 1] + - psum[i-1][j-1] + a[i][j];
}

// 꼭짓점이 (x,y)이고, 반대편이 (nx, ny)인 사각형의 합을 반환합니다.
int rectSum(int x, int y, int nx, int ny){
    return psum[nx][ny] - (psum[nx][y-1] + psum[x-1][ny]) + psum[x-1][y-1];
}

// 그림(a)에 표현된 사각형 2개의 포지션입니다.
void LeftUp_RightDown(int x, int y){
    mp.clear();
    for (int i = x; i >= 1; i--) {
        for (int j = y; j >= 1; j--) {
            int rect = rectSum(i, j, x, y);
            if (mp.count(rect)) mp[rect]++;
            else mp[rect] = 1;
        }
    }
    for (int i = x + 1; i <= n; i++) {
        for (int j = y + 1; j <= n; j++) {
            int rect = rectSum(x + 1, y + 1, i, j);
            if (mp.count(rect)) ans += mp[rect];
        }
    }
}

// 그림(b)에 표현된 사각형 2개의 포지션입니다.
void LeftDown_RightUp(int x, int y){
    mp.clear();
    for (int i = x; i >= 1; i--) {
        for (int j = y; j <= n; j++) {
            int rect = rectSum(i, y, x, j);
            if (mp.count(rect)) mp[rect]++;
            else mp[rect] = 1;
        }
    }
    for (int i = x + 1; i <= n; i++) {
        for (int j = y - 1; j >= 1; j--) {
            int rect = rectSum(x + 1, j, i, y - 1);
            if (mp.count(rect)) ans += mp[rect];
        }
    }
}
// 디버깅 다 해봤는데 틀리는 거 보면,, 시작점을 어떤 사각형에 포함하냐인듯
// 블로그에 올린 사람이랑 같은 범위의 사각형으로 시도해보기


int main(){
    //freopen("input.txt", "r", stdin);
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    rep(i, 1, n + 1) rep(j, 1, n + 1) cin >> a[i][j];
    precalc();

    rep(i, 1, n + 1){
        rep(j, 1, n + 1){
            LeftUp_RightDown(i, j);
            LeftDown_RightUp(i, j);
        }
    }
    cout << ans << '\n';

    return 0;
}

구현 후 코드리뷰 + 예제 돌려보기(x)

디버깅(x)

좋은 코드

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;
const int c=2500000;


int n;
int a[101][101];

int bio[2*c];
int pp[101][101];

int val (int x1,int y1,int x2,int y2)
{
    if ( x1 > 0)
    {
        if (y1 > 0)
        {
            return (pp[x2][y2]+pp[x1-1][y1-1]-pp[x1-1][y2]-pp[x2][y1-1]);
        }
        else
        {
            return (pp[x2][y2]-pp[x1-1][y2]);
        }
    }
    else
    {
        if (y1 > 0)
        {
            return (pp[x2][y2]-pp[x2][y1-1]);
        }
        else
        {
            return pp[x2][y2];
        }
    }
}
int main()
{
    cin>>n;
    for (int i=0; i<n; i++)
        for (int j=0; j<n; j++)
            cin>>a[i][j];

    pp[0][0]=a[0][0];

    for (int i=1; i<n; i++)
        {
            pp[i][0]=pp[i-1][0]+a[i][0];
            pp[0][i]=pp[0][i-1]+a[0][i];
        }

    for (int i=1; i<n; i++)
        for (int j=1; j<n; j++)
        pp[i][j]=pp[i][j-1]+pp[i-1][j]-pp[i-1][j-1]+a[i][j];

    int rj=0;

    for (int i=1; i<n; i++)
        for (int j=1; j<n; j++)
        {
            for (int x = 0; x < i; x++)
                for (int y=0; y < j; y++)
                    bio[val(x,y,i-1,j-1)+c]++;

            for (int x = i; x < n; x++)
                for (int y=j; y < n; y++)
                        rj+=bio[val(i,j,x,y)+c];

            for (int x = 0; x < i; x++)
                for (int y=0; y < j; y++)
                    bio[val(x,y,i-1,j-1)+c]--;


            for (int x = 0; x < i; x++)
                for (int y=j; y < n; y++)
                    bio[val(x,j,i-1,y)+c]++;

            for (int x = i; x < n; x++)
                for (int y = 0; y < j; y++)
                        rj+=bio[val(i,y,x,j-1)+c];

            for (int x = 0; x < i; x++)
                for (int y=j; y < n; y++)
                    bio[val(x,j,i-1,y)+c]--;


        }
    cout<<rj<<endl;
    //end = clock();
    //cout<< (double)(end - begin) / CLOCKS_PER_SEC<<endl;
    return 0;
}

최적화