-
AMUSEMENTPARK 놀이 공원 / algospot.comALGOSPOT 2020. 1. 28. 18:38728x90
문제링크 : https://algospot.com/judge/problem/read/AMUSEMENTPARK
제출링크 : CPP 코드로 제출한 링크 https://algospot.com/judge/submission/detail/653294
CPP 소스 : https://github.com/skysign/WSAPT/blob/master/algospot.com/AMUSEMENTPARK_cpp/AMUSEMENTPARK/AMUSEMENTPARK.cpp
자바 소스 : https://github.com/skysign/WSAPT/blob/master/algospot.com/AMUSEMENTPARK_java/src/Main.java정확한 이유는 잘 모르겠지만, 자바코드로 작성해서 올리면, '시간초과'로 정답 처리가 되지 않습니다.
맞게 코딩한 것 같은대, 계속 정답처리가 안되서, 같은 방식으로 cpp로 코딩했더니,
정답 처리가 되네요. cpp 코드는 AMUSEMENTPARK_cpp 폴더 참고하세요.오렌지가 멜론을 볼 수 있는 회수와 볼 수 있는 위치를 알아내는 문제입니다.
두친구가 이동하는 경로는 동일하지만, 시작하는 위치가 서로 다릅니다.
이동할 위치를 먼저 저장하는 코드를 작성해보겠습니다.int[] posIs = new int[M*N+1]; int[] posJs = new int[M*N+1]; int cntPos = 0; for(int i=0; i<M; ++i) { for(int j=0; j<N; ++j) { mMap[i][j] = sc.nextInt(); if(mMap[i][j] > 0) { posIs[mMap[i][j]] = i; posJs[mMap[i][j]] = j; cntPos++; } } }
이중루프를 한번만 사용하면서, 동시에 지도를 입력받고, 이동경로도 저장하는 것이 중요한 포인트입니다.
이후에 for( ; i<=cntPos; ) 이와 같은 루프를 사용해서, 오렌지와 멜론이 이동하는 것을 코딩할 수 있습니다.바로 옆에 있으면 보인다
오렌지와 멜론이 바로 옆에 있으면, 중간에 가로 막을 수 있는 것이 없으므로, 항상 볼 수 있습니다.
멜론을 기준으로, 오렌지가 옆에 있는지public boolean AreTheyAdjacent(int Oi, int Oj, int Mi, int Mj) { int[] di = new int[]{-1, 1, 0, 0, -1, -1, 1, 1}; int[] dj = new int[]{0, 0, -1, 1, -1, 1, 1, -1}; for(int k=0; k<di.length; ++k) { if((Oi == (Mi + di[k])) && (Oj == (Mj + dj[k]))) return true; } return false; }
같은 행 또는 열에 있는 경우
오렌지와 멜론의 i 또는 j값이 동일 합니다. 중간이 모두 비어 있으면 볼 수 있습니다.
// i 가 같음 if(Oi == Mi) { int fixedI = Oi; int begJ = Math.min(Oj, Mj) +1; int endJ = Math.max(Oj, Mj); for(int j = begJ; j < endJ; ++j) { if(mMap[fixedI][j] != 0) { return true; } } return false; } // j 가 같음 if(Oj == Mj) { int fixedJ = Oj; int begI = Math.min(Oi, Mi) +1; int endI = Math.max(Oi, Mi); for(int i = begI; i < endI; ++i) { if(mMap[i][fixedJ] != 0) { return true; } } return false; }
대각선에 있는 경우? 중간이 막혔을까? 아닐까?
이문제 가장 중요한 부분으로 생각합니다. 대각선에 오렌지와 멜론이 위치할 때, 오렌지가 멜론을 볼 수 있는지 여부를 구현하는 부분입니다.
di와 dj를 계산하고, 두 숫자가 모두 소수이면, 중간에 막을 수 있는 위치가 없습니다.
int di = Math.abs(Oi - Mi); int dj = Math.abs(Oj - Mj); // di와 dj 가 둘다 소수이면 // 중간에 시선을 막는 부분이 존재 하지 않음 if(AreTheyPrimeNumber(di, dj)) return false; public boolean AreTheyPrimeNumber(int a, int b) { int min = Math.min(a, b); for(int i=2; i<=min; ++i) { if ((a%i == 0) && (b%i == 0)) { return false; } } return true; }
우선 문제에 나와 있는대로, 오렌지(0,0) 멜론(2,2)의 경우를 생각해 보면, (1,1)이 0이면 볼 수 있고, 다른 숫자이면 볼 수 없습니다.
여기서 한가지 더 생각해야 할 경우가 있습니다.
오렌지(0,0) 멜론(3,6) 이런 경우에 오렌지가 멜론을 볼 수 있으려면,
중간에 2개의 위치(1,2) 와 (2,4)가 0 이어야 볼 수 있습니다.
오렌지가 멜론에게 다가간다고 생각하고, 중간에 막고있는 블럭이 모두 0인지 확인해 보는 코드입니다.int gcd = gcd(di, dj); di = (Mi - Oi) / gcd; dj = (Mj - Oj) / gcd; for(int step=1, i = Oi, j = Oj; step<gcd; ++step) { i += di; j += dj; if(mMap[i][j] != 0) return true; }
전체 소스코드는 아래와 같습니다.
import java.io.*; import java.util.ArrayList; import java.util.Scanner; /** * AMUSEMENTPARK 놀이 공원 / algospot.com * 문제링크 : https://algospot.com/judge/problem/read/AMUSEMENTPARK * 제출링크 : CPP 코드 https://algospot.com/judge/submission/detail/653294 * * 정확한 이유는 잘 모르겠지만, 자바코드로 작성해서 올리면, '시간초과'로 정답 처리가 되지 않습니다. * 맞게 코딩한 것 같은대, 계속 정답처리가 안되서, 같은 방식으로 cpp로 코딩했더니, * 정답 처리가 되네요. cpp 코드는 AMUSEMENTPARK_cpp 폴더 참고하세요. */ public class Main { int[][] mMap; public void solve() throws IOException { // Scanner sc = new Scanner(System.in); Reader sc = new Reader(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); int M = sc.nextInt(); int N = sc.nextInt(); int MelonPos = sc.nextInt(); mMap = new int[M][N]; // 정답 저장 ArrayList<Integer> mR = new ArrayList(); int[] posIs = new int[M*N+1]; int[] posJs = new int[M*N+1]; int cntPos = 0; for(int i=0; i<M; ++i) { for(int j=0; j<N; ++j) { mMap[i][j] = sc.nextInt(); if(mMap[i][j] > 0) { posIs[mMap[i][j]] = i; posJs[mMap[i][j]] = j; cntPos++; } } } for(int mPos=MelonPos, oPos=1; mPos<=cntPos; ++mPos, ++oPos) { if(true == AreTheyAdjacent(posIs[oPos], posJs[oPos], posIs[mPos], posJs[mPos])) { mR.add(oPos); } else if(false == AreTheyBlocked(posIs[oPos], posJs[oPos], posIs[mPos], posJs[mPos])) { mR.add(oPos); } } bw.write(mR.size()+"\n"); for(int r : mR) { bw.write(r+"\n"); } bw.close(); } public boolean AreTheyAdjacent(int Oi, int Oj, int Mi, int Mj) { int[] di = new int[]{-1, 1, 0, 0, -1, -1, 1, 1}; int[] dj = new int[]{0, 0, -1, 1, -1, 1, 1, -1}; for(int k=0; k<di.length; ++k) { if((Oi == (Mi + di[k])) && (Oj == (Mj + dj[k]))) return true; } return false; } public boolean AreTheyBlocked(int Oi, int Oj, int Mi, int Mj) { // i 가 같음 if(Oi == Mi) { int fixedI = Oi; int begJ = Math.min(Oj, Mj) +1; int endJ = Math.max(Oj, Mj); for(int j = begJ; j < endJ; ++j) { if(mMap[fixedI][j] != 0) { return true; } } return false; } // j 가 같음 if(Oj == Mj) { int fixedJ = Oj; int begI = Math.min(Oi, Mi) +1; int endI = Math.max(Oi, Mi); for(int i = begI; i < endI; ++i) { if(mMap[i][fixedJ] != 0) { return true; } } return false; } int di = Math.abs(Oi - Mi); int dj = Math.abs(Oj - Mj); // di와 dj 가 둘다 소수이면 // 중간에 시선을 막는 부분이 존재 하지 않음 if(AreTheyPrimeNumber(di, dj)) return false; // Orange와 Melon이 대각선 방향에 있음 // Orange에서 Melon방향으로 다가갈 때, // 중간이 막혀 있으면 blocked(true) int gcd = gcd(di, dj); di = (Mi - Oi) / gcd; dj = (Mj - Oj) / gcd; for(int step=1, i = Oi, j = Oj; step<gcd; ++step) { i += di; j += dj; if(mMap[i][j] != 0) return true; } return false; } public boolean AreTheyPrimeNumber(int a, int b) { int min = Math.min(a, b); for(int i=2; i<=min; ++i) { if ((a%i == 0) && (b%i == 0)) { return false; } } return true; } public int gcd(int a,int b) { if(b==0) return a; return gcd(b, a%b); } public static void main(String[] args) throws IOException { Main main = new Main(); main.solve(); } // https://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/ static class Reader { final private int BUFFER_SIZE = 1 << 16; private DataInputStream din; private byte[] buffer; private int bufferPointer, bytesRead; public Reader() { din = new DataInputStream(System.in); buffer = new byte[BUFFER_SIZE]; bufferPointer = bytesRead = 0; } public Reader(String file_name) throws IOException { din = new DataInputStream(new FileInputStream(file_name)); buffer = new byte[BUFFER_SIZE]; bufferPointer = bytesRead = 0; } public String nextLine() throws IOException { byte[] buf = new byte[64]; // line length int cnt = 0, c; while ((c = read()) != -1) { if (c == '\n') break; buf[cnt++] = (byte) c; } return new String(buf, 0, cnt); } public int nextInt() throws IOException { int ret = 0; byte c = read(); while (c <= ' ') c = read(); boolean neg = (c == '-'); if (neg) c = read(); do { ret = ret * 10 + c - '0'; } while ((c = read()) >= '0' && c <= '9'); if (neg) return -ret; return ret; } public long nextLong() throws IOException { long ret = 0; byte c = read(); while (c <= ' ') c = read(); boolean neg = (c == '-'); if (neg) c = read(); do { ret = ret * 10 + c - '0'; } while ((c = read()) >= '0' && c <= '9'); if (neg) return -ret; return ret; } public double nextDouble() throws IOException { double ret = 0, div = 1; byte c = read(); while (c <= ' ') c = read(); boolean neg = (c == '-'); if (neg) c = read(); do { ret = ret * 10 + c - '0'; } while ((c = read()) >= '0' && c <= '9'); if (c == '.') { while ((c = read()) >= '0' && c <= '9') { ret += (c - '0') / (div *= 10); } } if (neg) return -ret; return ret; } private void fillBuffer() throws IOException { bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE); if (bytesRead == -1) buffer[0] = -1; } private byte read() throws IOException { if (bufferPointer == bytesRead) fillBuffer(); return buffer[bufferPointer++]; } public void close() throws IOException { if (din == null) return; din.close(); } } }
728x90'ALGOSPOT' 카테고리의 다른 글
TRIANGLEPATH 삼각형 위의 최대 경로 / ALGOSPOT (0) 2020.02.05 QUADTREE 쿼드 트리 뒤집기 / ALGOSPOT (0) 2020.02.03 BOGGLE 보글 게임 / ALGOSPOT (0) 2020.02.02 AMUSEMENTPARK 놀이 공원 테스트케이스/ algospot.com (0) 2020.01.28 FESTIVAL 록 페스티벌 / algospot.com (0) 2020.01.28