반응형

https://www.acmicpc.net/problem/23290

 

23290번: 마법사 상어와 복제

첫째 줄에 물고기의 수 M, 상어가 마법을 연습한 횟수 S가 주어진다. 둘째 줄부터 M개의 줄에는 물고기의 정보 fx, fy, d가 주어진다. (fx, fy)는 물고기의 위치를 의미하고, d는 방향을 의미한다. 방향

www.acmicpc.net

물고기를 한마리 한마리 처리하는 게 아니라

같은 좌표에서 같은 방향을 가리키는 물고기가 몇마리 있는 지 세어주는 식으로 구현하면

메모리를 상당히 아낄 수 있다.

 

처음에 문제를 읽을 때는 물고기 한마리 한마리 벡터에 넣어주면서 풀었는데

어차피 중요한건 물고기의 수이므로 같은 좌표 같은 방향 물고기를 한번에 이동시켜주면

메모리와 함께 시간도 절약할 수 있다.

 

그리고 상어의 이동은 3칸이동하므로 간단히 반복문으로 구현하고

이동 내에서 중복된 칸이 있는지 체크하기 위해 set을 이용하여 여러번 방문한 칸이어도

물고기들을 한번만 없애주도록 만들었다.

 

#include <bits/stdc++.h>

using namespace std;

int skx, sky, S, smell[5][5];
int fishes[5][5][9], fishCopy[5][5][9];

void Input() {
    int M;
    cin >> M >> S;
    for (int i = 1; i <= M; i++) {
        int fx, fy, d;
        cin >> fx >> fy >> d;
        fishes[fx][fy][d]++;
    }
    cin >> skx >> sky;
}

void copyMagic() {
    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 4; j++) {
            for (int k = 1; k <= 8; k++) {
                fishCopy[i][j][k] = fishes[i][j][k];
            }
        }
    }
}

void fishesMove() {
    int dx[9] = {0, 0, -1, -1, -1, 0, 1, 1, 1};
    int dy[9] = {0, -1, -1, 0, 1, 1, 1, 0, -1};

    int tmp[5][5][9];
    memset(tmp, 0, sizeof(tmp));
    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 4; j++) {
            for (int k = 1; k <= 8; k++) {
                int dir = k;
                bool flag = false;
                for (int t = 1; t <= 8; t++) {
                    int nx = i + dx[dir];
                    int ny = j + dy[dir];
                    if (nx <= 0 || nx > 4 || ny <= 0 || ny > 4 || smell[nx][ny] || (nx == skx && ny == sky)) {
                        //반시계회전
                        dir = dir - 1;
                        if (dir == 0) dir = 8;
                    } else {
                        flag = true;
                        tmp[nx][ny][dir] += fishes[i][j][k];
                        break;
                    }
                }
                //이동할 수 없는 경우
                if (!flag) {
                    tmp[i][j][k] += fishes[i][j][k];
                }
            }
        }
    }
    swap(tmp, fishes);
}

void sharkMove() {
    int dx[5] = {0, -1, 0, 1, 0};
    int dy[5] = {0, 0, -1, 0, 1};

    int maxSum = -1;
    int nskx = -1, nsky = -1;
    vector<pair<int, int> > toSmell;
    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 4; j++) {
            for (int k = 1; k <= 4; k++) {
                int firstX = skx + dx[i], firstY = sky + dy[i];
                int secX = firstX + dx[j], secY = firstY + dy[j];
                int thirdX = secX + dx[k], thirdY = secY + dy[k];

                if (firstX <= 0 || firstX > 4 || firstY <= 0 || firstY > 4) continue;
                if (secX <= 0 || secX > 4 || secY <= 0 || secY > 4) continue;
                if (thirdX <= 0 || thirdX > 4 || thirdY <= 0 || thirdY > 4) continue;
                int sum = 0;
                set<pair<int, int> > Set;
                Set.insert({firstX, firstY});
                Set.insert({secX, secY});
                Set.insert({thirdX, thirdY});
                for (auto a: Set) {
                    for(int b=1; b<=8; b++){
                        sum += fishes[a.first][a.second][b];
                    }
                }
                if (sum > maxSum) {
                    maxSum = sum;
                    toSmell.clear();
                    nskx = thirdX;
                    nsky = thirdY;
                    for (auto a: Set) {
                        toSmell.push_back({a.first, a.second});
                    }
                }
            }
        }
    }
    for (auto a: toSmell) {
        int sum = 0;
        for(int b=1; b<=8; b++){
            sum += fishes[a.first][a.second][b];
        }
        if (sum) {
            smell[a.first][a.second] = 3;
            memset(fishes[a.first][a.second], 0 ,sizeof(fishes[a.first][a.second]));
        }
    }
    skx = nskx;
    sky = nsky;
}

void smellErase() {
    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 4; j++) {
            if (smell[i][j]) {
                smell[i][j]--;
            }
        }
    }
}

void appendCopy() {
    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 4; j++) {
            for(int k=1; k<=8 ;k++){
                fishes[i][j][k] += fishCopy[i][j][k];
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    Input();
    for (int i = 0; i < S; i++) {
        copyMagic();
        fishesMove();
        sharkMove();
        smellErase();
        appendCopy();
    }

    int ans = 0;
    for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 4; j++) {
            for(int k=1; k<=8 ;k++){
                ans += fishes[i][j][k];
            }
        }
    }

    cout << ans << '\n';

    return 0;
}
반응형
반응형

https://www.acmicpc.net/problem/23289

 

23289번: 온풍기 안녕!

유난히 추운 날씨가 예상되는 이번 겨울을 대비하기 위해 구사과는 온풍기를 설치하려고 한다. 온풍기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기

www.acmicpc.net

문제를 해결하기 위해서는 상당한 기합이 필요하다..

 

 

#include <bits/stdc++.h>

using namespace std;

int chocolate, R, C, K, W, Map[21][21];
bool Wall[21][21][4];
vector<pair<int, int> > toCheck;
vector<tuple<int, int, int> > hotAirBlower;

void warmAir() {
    int dx[4] = {0, 0, -1, 1};
    int dy[4] = {1, -1, 0, 0};

    //hd, x, y
    int nextDir[4][2][3] = {
            {{-1, 0,  1},  {1,  1,  1}},
            {{-1, 0,  1},  {-1, -1, -1}},
            {{-1, -1, -1}, {1,  0,  -1}},
            {{1,  1,  1},  {1,  0,  -1}}
    };

    for (auto h: hotAirBlower) {
        int addWarm[21][21];
        memset(addWarm, 0, sizeof(addWarm));

        auto [hx, hy, hd] = h;
        queue<pair<int, int> > Q;
        int stx = hx + dx[hd];
        int sty = hy + dy[hd];

        Q.push({stx, sty});
        addWarm[stx][sty] = 5;
        while (!Q.empty()) {
            int x = Q.front().first;
            int y = Q.front().second;
            Q.pop();

            if (addWarm[x][y] == 1) continue;
            for (int i = 0; i < 3; i++) {
                int nx = x + nextDir[hd][0][i];
                int ny = y + nextDir[hd][1][i];

                if (nx <= 0 || nx > R || ny <= 0 || ny > C) continue;
                if (addWarm[nx][ny]) continue;
                //사이에 벽이 있는 경우
                if (abs(nx - x) && abs(ny - y)) { //대각선
                    if (hd == 0) {
                        if (nx - x > 0) {
                            if (Wall[x][y][2] || Wall[nx][ny][3]) continue;
                        } else {
                            if (Wall[x][y][0] || Wall[nx][ny][3]) continue;
                        }
                    } else if (hd == 1) {
                        if (nx - x > 0) {
                            if (Wall[x][y][2] || Wall[nx][ny][1]) continue;
                        } else {
                            if (Wall[x][y][0] || Wall[nx][ny][1]) continue;
                        }
                    } else if (hd == 2) {
                        if (ny - y > 0) {
                            if (Wall[x][y][1] || Wall[nx][ny][2]) continue;
                        } else {
                            if (Wall[x][y][3] || Wall[nx][ny][2]) continue;
                        }
                    } else {
                        if (ny - y > 0) {
                            if (Wall[x][y][1] || Wall[nx][ny][0]) continue;
                        } else {
                            if (Wall[x][y][3] || Wall[nx][ny][0]) continue;
                        }
                    }
                } else {
                    if (nx - x == 1 && Wall[x][y][2]) continue;
                    else if (nx - x == -1 && Wall[x][y][0])continue;
                    else if (ny - y == 1 && Wall[x][y][1]) continue;
                    else if (ny - y == -1 && Wall[x][y][3]) continue;
                }
                addWarm[nx][ny] = addWarm[x][y] - 1;

                Q.push({nx, ny});
            }
        }

        for (int i = 1; i <= R; i++) {
            for (int j = 1; j <= C; j++) {
                Map[i][j] += addWarm[i][j];
            }
        }

    }
}

void temperatureControl() {
    int tmp[21][21];
    int dx[4] = {0, 0, -1, 1};
    int dy[4] = {1, -1, 0, 0};


    for (int x = 1; x <= R; x++) {
        for (int y = 1; y <= C; y++) {
            int curTemper = Map[x][y];
            int sum = 0;
            int minus = 0;

            for (int k = 0; k < 4; k++) {
                int nx = x + dx[k];
                int ny = y + dy[k];

                if (nx <= 0 || nx > R || ny <= 0 || ny > C) continue;
                //벽
                if (nx - x == 1 && Wall[x][y][2]) continue;
                else if (nx - x == -1 && Wall[x][y][0])continue;
                else if (ny - y == 1 && Wall[x][y][1]) continue;
                else if (ny - y == -1 && Wall[x][y][3]) continue;

                if (Map[nx][ny] > Map[x][y]) {
                    sum += abs(Map[nx][ny] - Map[x][y]) / 4;
                } else if (Map[nx][ny] < Map[x][y]) {
                    minus += abs(Map[nx][ny] - Map[x][y]) / 4;
                }
            }
            tmp[x][y] = curTemper + sum - minus;
        }
    }
    swap(tmp, Map);
}

void temperatureMinus() {
    for (int i = 1; i <= R; i++) {
        if (Map[i][1]) Map[i][1]--;
        if (Map[i][C]) Map[i][C]--;
    }
    for (int i = 2; i <= C-1; i++) {
        if (Map[1][i]) Map[1][i]--;
        if (Map[R][i]) Map[R][i]--;
    }
}

bool endCheck() {
    if(chocolate > 100) return true;
    for (auto a: toCheck) {
        if (Map[a.first][a.second] < K) return false;
    }
    return true;
}

void Input() {
    cin >> R >> C >> K;
    for (int i = 1; i <= R; i++) {
        for (int j = 1; j <= C; j++) {
            int num;
            cin >> num;
            if (num == 5) {
                toCheck.push_back({i, j});
            } else if (num > 0) {
                hotAirBlower.push_back({i, j, num - 1});
            }
        }
    }
    cin >> W;
    for (int i = 1; i <= W; i++) {
        int x, y, t;
        cin >> x >> y >> t;
        if (t == 0) {
            Wall[x][y][0] = 1;
            Wall[x - 1][y][2] = 1;
        } else {
            Wall[x][y][1] = 1;
            Wall[x][y + 1][3] = 1;
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    Input();

    do {
        warmAir();
        temperatureControl();
        chocolate++;
        temperatureMinus();
    } while (!endCheck());

    cout << ((chocolate > 100) ? 101 : chocolate) << '\n';

    return 0;
}
반응형
반응형

https://www.acmicpc.net/problem/23288

 

23288번: 주사위 굴리기 2

크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 가장 왼

www.acmicpc.net

 

#include <bits/stdc++.h>

using namespace std;

int N, M, K, Map[21][21], pointMap[21][21], ans;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int moveDirection = 0;
//dice는 문제의 나온 전개도랑 다릅니다. 제가 문제에 제시된걸 안보고 풀어서 그렇습니다..
int dice[6] = {6, 5, 1, 2, 4, 3};
int floorX = 1, floorY = 1;

void drawPointMap() {
    queue<pair<int, int> > Q;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            if (pointMap[i][j] == 0) {
                vector<pair<int, int> > v;
                Q.push({i, j});
                //방문체크
                pointMap[i][j] = -1;
                v.push_back({i, j});

                while (!Q.empty()) {
                    int x = Q.front().first;
                    int y = Q.front().second;
                    Q.pop();

                    for (int k = 0; k < 4; k++) {
                        int nx = x + dx[k];
                        int ny = y + dy[k];
                        if (nx <= 0 || nx > N || ny <= 0 || ny > M) continue;
                        if (Map[nx][ny] == Map[i][j] && pointMap[nx][ny] != -1) {
                            Q.push({nx, ny});
                            v.push_back({nx, ny});
                            pointMap[nx][ny] = -1;
                        }
                    }
                }
                for (int k = 0; k < v.size(); k++) {
                    pointMap[v[k].first][v[k].second] = Map[i][j] * v.size();
                }
            }
        }
    }
}

void turnMoveDirection() {
    if (dice[0] > Map[floorX][floorY]) {
        moveDirection = (moveDirection + 1) % 4;
    } else if (dice[0] < Map[floorX][floorY]) {
        moveDirection = (moveDirection + 3) % 4;
    }
}

void diceToRight() {
    int tmp = dice[0];
    dice[0] = dice[5];
    dice[5] = dice[2];
    dice[2] = dice[4];
    dice[4] = tmp;
}

void diceToDown() {
    int tmp = dice[3];
    dice[3] = dice[0];
    dice[0] = dice[1];
    dice[1] = dice[2];
    dice[2] = tmp;
}


void checkAndMove() {
    // 아랫면 좌표 이동
    int x = floorX + dx[moveDirection];
    int y = floorY + dy[moveDirection];
    if (x <= 0 || x > N || y <= 0 || y > M) {
        moveDirection = (moveDirection + 2) % 4;
        x = floorX + dx[moveDirection];
        y = floorY + dy[moveDirection];
    }
    floorX = x;
    floorY = y;


    //주사위 이동
    if (moveDirection == 0) {
        diceToRight();
    } else if (moveDirection == 2) {
        for (int i = 0; i < 3; i++) diceToRight();
    } else if (moveDirection == 1) {
        diceToDown();
    } else {
        for (int i = 0; i < 3; i++) diceToDown();
    }
    
    ans += pointMap[floorX][floorY];
    turnMoveDirection();
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M >> K;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> Map[i][j];
        }
    }


    drawPointMap();

    for (int i = 1; i <= K; i++) checkAndMove();


    cout << ans << '\n';

    return 0;
}

 

반응형
반응형

https://www.acmicpc.net/problem/21611

 

21611번: 마법사 상어와 블리자드

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그, 비바라기 마법을 할 수 있다. 오늘 새로 배운 마법은 블리자드이고, 크기가 N×N인 격자에서 연습하려고 한다. N은 항상 홀수이고, (

www.acmicpc.net

1.문제설명

해당 문제에서 거쳐야하는 과정을 크게 4가지로 분리할 수 있다.

 

1. 블리자드해서 구슬을 삭제한다.

2. 구슬의 빈자리를 메꾸도록 모든 구슬을 앞으로 이동시킨다.

3. 구슬폭발 : 이동후 같은 구슬이 4개 이상 모여있는 구슬들을 삭제한다. (삭제후 2번과 동일하게 앞으로 이동)

4. 구슬변화 : 남아있는 구슬을 확인하면서, 연속된 구슬의 개수와 해당 구슬의 숫자로 구슬을 변화시킨다.

 

 

이 문제를 풀기 위한 배열과 연결리스트 중 어떤 자료구조를 선택할 지 고민했는데,

구슬폭발로 인해 원소를 자주 삭제해야하니까 연결리스트가 시간복잡도 상 유리하지 않을까 생각했다.

 

그런데 좀 더 생각해보니 구슬이 폭발한다고 원소를 바로 바로 삭제해서 푸는게 아니라

폭발하기 전 배열에서 폭발할 구슬들을 확인한 후 제외하는 방식으로 풀어야하기 때문에

인덱스 접근을 해야할 일이 많아서 배열로 푸는 것으로 결정했다.

 

 

의문이 들었던 것 중 하나는

4. 구슬변화 후 다시 구슬폭발이 일어나는 경우가 있지 않을 까 의심했는데,

깊이 생각해보니 구슬폭발이 모두 끝난 후에는 구슬 변화로 인해 연속적인 구슬 4개가 생길 수 없다.

예를 들어서 2가 2개 있는 경우, 또 2가 2개있는 경우 이러면 2222가 되니까 또 폭발할 수 있지 않을 까 생각했는데

애초에 구슬폭발이 모두 끝난 경우에는 2가 2개, 2가 2개 이런 경우가 나타날 수 없다.

다른 경우도 마찬가지이다.

 

 

문제에서 2차원 배열 형식으로 그림을 제공했지만

이를 1차원 배열로 전환한 후 문제를 해결해야한다.

반복문을 통해서 2차원배열의 1번부터 N*N-1번까지 돌 수 있다.

 

블리자드를 구현할 때는 1차원 배열내에서 가능한데,

계차수열을 이용해서 1차원 배열에서 반복문을 돌면서 배열의 원소를 지워나가면 해결할 수 있다.

 

2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;

int N, M, originArr[51][51], marbles[2501], ans[4];

void originToMarbles() {
    int x = (N + 1) / 2;
    int y = x;

    int dx[4] = {0, 1, 0, -1};
    int dy[4] = {-1, 0, 1, 0};

    int curDir = 0;
    int moveCnt = 1;
    int turnDirCnt = 0;

    for (int i = 0; i < N * N; i++) {
        marbles[i] = originArr[x][y];
        turnDirCnt++;

        x += dx[curDir];
        y += dy[curDir];

        if (turnDirCnt == moveCnt) {
            if (curDir == 1 || curDir == 3) moveCnt++;
            curDir = (curDir + 1) % 4;
            turnDirCnt = 0;
        }
    }
}

void blizzard(int d, int s) {
    int firstNum[5] = {0, 7, 3, 1, 5};
    int firstStep[5] = {0, 15, 11, 9, 13};

    int num = firstNum[d];
    int step = firstStep[d];
    for (int i = 1; i <= s; i++) {
        marbles[num] = 0;
        num += step;
        step += 8;
    }
}

void marbleMove() {
    int tmp[2501];
    memset(tmp, 0, sizeof(tmp));
    int tmpIdx = 1;

    for (int i = 1; i < N * N; i++) {
        if (marbles[i] == 0) continue;
        tmp[tmpIdx++] = marbles[i];
    }
    swap(marbles, tmp);
}

bool marbleExplode() {
    bool flag = false;
    int sameFirst = 1;
    int sameCnt = 1;
    for (int i = 2; i <= N * N; i++) {
        if (marbles[i] != 0 && marbles[i] == marbles[i - 1]) {
            sameCnt++;
        } else {
            if (sameCnt >= 4) {
                ans[marbles[i-1]] += i - sameFirst;
                for (int j = sameFirst; j <= i - 1; j++) {
                    marbles[j] = 0;
                }
                flag = true;
            }
            sameFirst = i;
            sameCnt = 1;
        }
    }
    return flag;
}

void marbleChange() {
    int tmp[2501];
    memset(tmp, 0 ,sizeof(tmp));
    int tmpIdx = 1;

    int sameCnt = 1;
    for(int i=2; i<=N*N; i++){
        if(marbles[i]==marbles[i-1]){
            sameCnt++;
        }
        else{
            tmp[tmpIdx++] = sameCnt;
            if(tmpIdx == N*N) break;
            tmp[tmpIdx++] = marbles[i-1];
            if(tmpIdx == N*N) break;
            sameCnt = 1;
        }
    }
    swap(tmp, marbles);
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            cin >> originArr[i][j];
        }
    }

    originToMarbles();


    for (int i = 1; i <= M; i++) {
        int d, s;
        cin >> d >> s;
        blizzard(d, s);
        marbleMove();
        while (marbleExplode()) {
            marbleMove();
        }
        marbleChange();
    }
    
    cout << ans[1] + 2 * ans[2] + 3 * ans[3] << '\n';
    return 0;
}

 

반응형
반응형

https://www.acmicpc.net/problem/21610

 

21610번: 마법사 상어와 비바라기

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;

int N, M, A[51][51];
bool cloudCheck[51][51];
vector<pair<int, int>> cloudPosition;

int dx[8] = {0, -1, -1, -1, 0, 1, 1, 1};
int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1};

void cloudMove(int d, int s) {
  for (int i = 0; i < cloudPosition.size(); i++) {
    int x = cloudPosition[i].first;
    int y = cloudPosition[i].second;

    int nx = (x + dx[d] * s) % N;
    nx = nx <= 0 ? nx + N : nx;

    int ny = (y + dy[d] * s) % N;
    ny = ny <= 0 ? ny + N : ny;

    cloudCheck[nx][ny] = 1;
    A[nx][ny]++;

    cloudPosition[i].first = nx;
    cloudPosition[i].second = ny;
  }
}

void waterCopyBug() {
  for (int i = 0; i < cloudPosition.size(); i++) {
    int x = cloudPosition[i].first;
    int y = cloudPosition[i].second;

    int cnt = 0;
    for (int j = 1; j < 8; j += 2) {
      int nx = x + dx[j];
      int ny = y + dy[j];

      if (nx <= 0 || nx > N || ny <= 0 || ny > N)
        continue;

      if (A[nx][ny] > 0)
        cnt++;
    }

    A[x][y] += cnt;
  }
}

void makeCloud() {
  cloudPosition.clear();
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      if (!cloudCheck[i][j] && A[i][j] >= 2) {
        cloudPosition.push_back({i, j});
        A[i][j] -= 2;
      }
    }
  }

  memset(cloudCheck, 0, sizeof(cloudCheck));
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);

  cin >> N >> M;
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      cin >> A[i][j];
    }
  }

  cloudPosition.push_back({N, 1});
  cloudPosition.push_back({N, 2});
  cloudPosition.push_back({N - 1, 1});
  cloudPosition.push_back({N - 1, 2});

  for (int i = 1; i <= M; i++) {
    int d, s;
    cin >> d >> s;
    cloudMove(d - 1, s);
    waterCopyBug();
    makeCloud();
  }

  int ans = 0;
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      ans += A[i][j];
    }
  }

  cout << ans;
  return 0;
}
반응형
반응형

https://www.acmicpc.net/problem/21608

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;

int N, num, seat[21][21], student[401][4];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

bool isInLikeStudent(int cur, int x, int y) {
  for (int i = 0; i < 4; i++) {
    if (student[cur][i] == seat[x][y])
      return true;
  }
  return false;
}

void sitDownOneByOne(int cur) {
  int resX = -1, resY = -1;
  //여기가 중요한 포인트! 0 / 0인 경우가 정답이 될 수 있다
  int maxLikeStudents = -1, maxEmpties = -1;

  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
      int likeStudents = 0;
      int empty = 0;

      if (seat[i][j] > 0)
        continue;
      for (int k = 0; k < 4; k++) {
        int nx = i + dx[k];
        int ny = j + dy[k];
        if (nx <= 0 || nx > N || ny <= 0 || ny > N)
          continue;
        if (seat[nx][ny] == 0) {
          empty++;
        } else if (isInLikeStudent(cur, nx, ny)) {
          likeStudents++;
        }
      }

      if (likeStudents > maxLikeStudents) {
        maxLikeStudents = likeStudents;
        maxEmpties = empty;
        resX = i;
        resY = j;
      } else if (likeStudents == maxLikeStudents) {
        if (empty > maxEmpties) {
          maxEmpties = empty;
          resX = i;
          resY = j;

        } else if (empty == maxEmpties) {
          if (resX == i && resY > j) {
            resY = j;
          } else if (resX > i) {
            resX = i;
            resY = j;
          }
        }
      }
    }
  }

  seat[resX][resY] = cur;
}

void Input() {
  cin >> N;
  num = N * N;
  for (int i = 1; i <= num; i++) {
    int cur;
    cin >> cur;
    for (int j = 0; j < 4; j++) {
      cin >> student[cur][j];
    }
    sitDownOneByOne(cur);
  }
}

int calAns() {
  int ans = 0;
  for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {

      int myFriends = 0;
      for (int k = 0; k < 4; k++) {
        int nx = i + dx[k];
        int ny = j + dy[k];

        if (nx <= 0 || nx > N || ny <= 0 || ny > N)
          continue;
        if (isInLikeStudent(seat[i][j], nx, ny)) {
          myFriends++;
        }
      }
      if (myFriends == 1) {
        ans += 1;
      } else if (myFriends == 2) {
        ans += 10;
      } else if (myFriends == 3) {
        ans += 100;
      } else if (myFriends == 4) {
        ans += 1000;
      }
    }
  }

  return ans;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  Input();
  cout << calAns() << '\n';

  return 0;
}
반응형
반응형

https://www.acmicpc.net/problem/20058

 

20058번: 마법사 상어와 파이어스톰

마법사 상어는 파이어볼과 토네이도를 조합해 파이어스톰을 시전할 수 있다. 오늘은 파이어스톰을 크기가 2N × 2N인 격자로 나누어진 얼음판에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c

www.acmicpc.net

#include <bits/stdc++.h>

using namespace std;

int N,rows, Q,L, A[64][64];
int dx[4] = {1,0,-1,0};
int dy[4] = {0,1,0,-1};

void TurnBox(int x, int y, int len){
    int retBox[len][len];

    for(int i=0; i<len; i++) {
        for (int j = 0; j < len; j++) {
            retBox[j][len-1-i] = A[x+i][y+j];
        }
    }

    for(int i=0; i<len; i++) {
        for (int j = 0; j < len; j++) {
            A[x+i][y+j] = retBox[i][j];
        }
    }

}


void Turn(int _L){
    int box = pow(2,N) / pow(2, _L);
    int len = pow(2,_L);

    for(int i=0; i<box ;i++){
        for(int j=0; j<box; j++) {
            int x = i*len;
            int y = j*len;

            TurnBox(x,y,len);
        }
    }
}

void Melt(){
    vector<pair<int,int> > willMelt;

    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            int cnt = 0;
            if(A[i][j]==0) continue;
            for(int k=0; k<4; k++){
                int nx = i + dx[k];
                int ny= j +dy[k];
                if(nx<0||nx>=rows||ny<0||ny>=rows) continue;
                if(A[nx][ny] > 0) cnt++;
            }
            if(cnt <3){
                willMelt.push_back({i,j});
            }
        }
    }

    for(int i=0; i<willMelt.size();i++){
        A[willMelt[i].first][willMelt[i].second]--;
    }
}

void Round(int _L){
    Turn(_L);
    Melt();
}


void Input();
int Count(){
    int sum = 0;
    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            sum += A[i][j];
        }
    }
    return sum;
}

int getMax(){
    bool ch[64][64] = {0};
    int ans = 0;
    queue<pair<int,int> > Q;

    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            if(!ch[i][j] && A[i][j]>0){
                ch[i][j] = 1;
                int cnt = 1;
                Q.push({i,j});

                while(!Q.empty()){
                    auto cur = Q.front(); Q.pop();

                    for(int k=0; k<4; k++){
                        int nx = cur.first + dx[k];
                        int ny= cur.second +dy[k];
                        if(nx<0||nx>=rows||ny<0||ny>=rows) continue;
                        if(ch[nx][ny] || A[nx][ny]==0) continue;
                        Q.push({nx,ny});
                        ch[nx][ny] = 1;
                        cnt++;

                    }
                }

                ans = max(ans, cnt);
            }
        }
    }


    return ans;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    Input();
    cout << Count() << '\n';
    cout << getMax() << '\n';

}

void Input() {
    cin >> N >> Q;
    rows = pow(2,N);
    for(int i=0; i<rows; i++){
        for(int j=0; j<rows; j++){
            cin >> A[i][j];
        }
    }
    for(int i=0; i<Q; i++){
        cin >> L;
        Round(L);
    }
}
반응형
반응형
https://www.acmicpc.net/problem/20057
 

20057번: 마법사 상어와 토네이도

마법사 상어가 토네이도를 배웠고, 오늘은 토네이도를 크기가 N×N인 격자로 나누어진 모래밭에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c열을 의미하고, A[r][c]는 (r, c)에 있는 모래의 양을

www.acmicpc.net

1.문제설명

토네이도의 이동 방법은 단순 반복이기 때문에

반복문으로 구현할 수 있다.

 

토네이도에 따라 모래가 이동하는 것을 잘 구현해야 한다.

항상 모래가 퍼지는 방법은 동일한데

토네이도의 이동방향에 따라 다르다.

 

토네이도의 이동방향을 기준으로

현재 이동방향과 수직에 놓여있는지,

아니면 현재 이동방향의 2칸 앞에 있는지

현재 토네이도가 이동한 위치와 이동했던 방향을 기준으로

함수를 만들면 4방향에 대해서 모두 처리해주지 않아도 된다.

 

 

 

2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;

int N, sum, sand[500][500];

void Input();


int dx[4] = {0, 1, 0, -1};
int dy[4] = {-1, 0, 1, 0};

bool inSand(int x, int y) {
    return (x >= 1 && x <= N && y >= 1 && y <= N);
}

void flySand(int x, int y, int dir) {
    int nx = x + dx[dir] * 2;
    int ny = y + dy[dir] * 2;
    int sum = 0;

    int num = int(sand[x][y] * 0.05);
    sum += num;
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }

    //수직

    num = int(sand[x][y] * 0.07);
    sum += num;
    nx = x + dx[(dir + 1) % 4];
    ny = y + dy[(dir + 1) % 4];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.07);
    sum += num;
    nx = x + dx[(dir + 3) % 4];
    ny = y + dy[(dir + 3) % 4];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.02);
    sum += num;
    nx = x + dx[(dir + 1) % 4] * 2;
    ny = y + dy[(dir + 1) % 4] * 2;
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.02);
    sum += num;
    nx = x + dx[(dir + 3) % 4] * 2;
    ny = y + dy[(dir + 3) % 4] * 2;
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    //수직

    num = int(sand[x][y] * 0.1);
    sum += num;
    nx = x + dx[(dir + 1) % 4] + dx[dir];
    ny = y + dy[(dir + 1) % 4] + dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.1);
    sum += num;
    nx = x + dx[(dir + 3) % 4] + dx[dir];
    ny = y + dy[(dir + 3) % 4] + dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    //수직\

    num = int(sand[x][y] * 0.01);
    sum += num;
    nx = x + dx[(dir + 1) % 4] - dx[dir];
    ny = y + dy[(dir + 1) % 4] - dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }


    num = int(sand[x][y] * 0.01);
    sum += num;
    nx = x + dx[(dir + 3) % 4] - dx[dir];
    ny = y + dy[(dir + 3) % 4] - dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += num;
    }

    nx = x + dx[dir];
    ny = y + dy[dir];
    if (inSand(nx, ny)) {
        sand[nx][ny] += sand[x][y] - sum;
    }

    sand[x][y] = 0;

}


void tornadoMove() {
    int x = N / 2 + 1, y = N / 2 + 1;
    int dir = 0;
    int moveBlocks = 1;
    int cnt = 0;

//    while(!(x==1 && y==1)){
    while (1) {
        for (int i = 0; i < moveBlocks; i++) {
            x += dx[dir];
            y += dy[dir];
            flySand(x, y, dir);

            if (x == 1 && y == 1) return;
        }
        cnt++;
        dir = (dir + 1) % 4;
        if (cnt == 2) {
            moveBlocks++;
            cnt = 0;
        }

    }
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);


    Input();
    tornadoMove();

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            sum -= sand[i][j];
        }
    }

    cout << sum << '\n';
}

void Input() {
    cin >> N;

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            cin >> sand[i][j];
            sum += sand[i][j];
        }
    }
}
반응형

+ Recent posts