문제 : https://www.acmicpc.net/problem/15684

 

15684번: 사다리 조작

사다리 게임은 N개의 세로선과 M개의 가로선으로 이루어져 있다. 인접한 세로선 사이에는 가로선을 놓을 수 있는데, 각각의 세로선마다 가로선을 놓을 수 있는 위치의 개수는 H이고, 모든 세로선이 같은 위치를 갖는다. 아래 그림은 N = 5, H = 6 인 경우의 그림이고, 가로선은 없다. 초록선은 세로선을 나타내고, 초록선과 점선이 교차하는 점은 가로선을 놓을 수 있는 점이다. 가로선은 인접한 두 세로선을 연결해야 한다. 단, 두 가로선이 연속하거나 서로

www.acmicpc.net

 

문제 요약 : i번째로 출발해 i가 나오도록 선을 긋는 최소 횟수

입력 출력

2 ≤ N(열) ≤ 10

1 ≤ H(행) ≤ 30

0 ≤ M(사다리) ≤ (N-1)*H

M개의 사다리값 

i번째로 출발해 i가 나오게 만드는 최소 조작 횟수 

 

 

JAVA - 수정 후

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16394816 cbkpar 15684 맞았습니다!! 15592KB 1796ms Java 1628B
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {

	static int n,m,h;
	static int[][] ladder;
	static int ans = 4;
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		int i;
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		h = Integer.parseInt(st.nextToken());

		ladder = new int[h][n];
		
		for(i=0;i<m;i++) {
			st = new StringTokenizer(br.readLine());
			ladder[Integer.parseInt(st.nextToken())-1][Integer.parseInt(st.nextToken())-1]=1;
		}
		if(m==0) {
			ans=0;
		}else {
		dfs(0,0);
		}
		ans=ans==4?-1:ans;
		bw.write(ans+"\n");
		br.close();
		bw.close();
	}
	static void dfs(int w, int k) {
		if(k>=ans) return; // 현재까지 구한 최솟값보다 같거나 크면 리턴
		int i;
		for(i=0;i<n-1;i++) { //n-1개가 똑같다면 나머지 하나는 당연히 같으므로 n까지 조사하지 않음
			int tmp = i;
			for(int j=0;j<h;j++) {
				if(ladder[j][tmp]==1) {//현재위치에 사다리가 있다면 오른쪽으로 한칸
					tmp++;
					continue;
				}
				if(tmp==0) continue;
				if(ladder[j][tmp-1]==1) {//현재위치-1에 사다리가 있으면 왼쪽으로 한칸
					tmp--;
					continue;
				}
			}
			if(tmp!=i) break;//시작한 사다리가 끝난 사다리와 다르면 종료
		}
		if(i==n-1&&k<ans) {//맞은 개수가 n-1개라면
			ans = k;
			return;
		}
		for(i=w;i<n*h;i++) {
			int dy = i/n;//초기값을 행렬안에 적지 않고 밖에 공통으로 적어줌
			int dx = i%n;
			if(i%n>0) {
				if(ladder[dy][dx-1]==1) continue; //왼쪽에 사다리가 있을경우 다음으로
			}
			if(i%n>=n-1) continue; //마지막에는 더이상 마지막으로 갈 수 없으므로 다음으로
			if(ladder[dy][dx+1]==1) continue; //오른쪽에 사다리가 있을 경우 다음으로
			if(ladder[dy][dx]==0) {
				ladder[dy][dx]=1;
				dfs(i+2,k+1);
                //사다리를 추가했을경우 연속할 수 없으므로 i+1이아닌 i+2로 한다.
				ladder[dy][dx]=0;
			}
		}
	}
}

느낀점 1: dy dx의 경우 i/n, i%n으로 행렬식 안에 넣었지만 이렇게 할경우 연산이 많아진다는 점 확인

 

느낀점 2: 연속할 경우에는 i+1번째가 아닌 그다음을 검사해도 된다.

 

느낀점 3: 1개만 틀릴 수 있는 경우는 존재 하지 않으므로 1번부터 n번까지 조사하지 않아도 된다.

 

느낀점 4:세로로 푸는것이아닌 가로로도 푸는 방법이 존재한다 행마다 열이 있는경우 결과를 바꿔주면된다.

//하지만 중간에 결과를 알 수 없고 끝까지 검사를 해야 한다는 단점이 있음

 

느낀점 5: 리스트로 미리 빈칸을 받거나 조건문을 개선하면 시간을 많이 단축 할 수 있을 것 같다.

 

 

 

 

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16385137 cbkpar 15684 맞았습니다!! 15812KB 2036ms Java 1549B
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {

	static int n,m,h;
	static int[][] ladder;
	static int ans = 4;
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		int i;
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		h = Integer.parseInt(st.nextToken());

		ladder = new int[h][n];
		
		for(i=0;i<m;i++) {
			st = new StringTokenizer(br.readLine());
			ladder[Integer.parseInt(st.nextToken())-1][Integer.parseInt(st.nextToken())-1]=1;
		}
		dfs(0,0);
		ans=ans==4?-1:ans;
		bw.write(ans+"\n");
		br.close();
		bw.close();
	}
	static void dfs(int w, int k) {
		if(k>=ans) return;
		int i;
		for(i=0;i<n;i++) {
			int tmp = i;
			for(int j=0;j<h;j++) {
				if(ladder[j][tmp]==1) {
					tmp++;
					continue;
				}
				if(tmp==0) continue;
				if(ladder[j][tmp-1]==1) {
					tmp--;
					continue;
				}
			}
			if(tmp!=i) break;
		}
		if(i==n) ans=Math.min(ans, k);
		for(i=w;i<n*h;i++) {
			if(i%n>0) {
				if(ladder[i/n][i%n-1]==1) continue;
			}
			if(i%n>=n-1) continue;
			if(ladder[i/n][i%n+1]==1) continue;
			if(ladder[i/n][i%n]==0) {
				ladder[i/n][i%n]=1;
				dfs(i+1,k+1);
				ladder[i/n][i%n]=0;
			}
		}
	}
}

문제 : https://www.acmicpc.net/problem/15683

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다. 1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할

www.acmicpc.net

문제 요약 : 사각지대 최소 크기 출력

입력 출력

1 ≤ N(세로) ≤ 8

1 ≤ M(가로) ≤ 8

0 ≤ [N][M](지도) ≤ 6

[0(빈 칸), 1~5(CCTV), 6(벽)]

사각지대 최소 크기 출력

 

 

JAVA - 수정 후

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16374743 cbkpar 15683 맞았습니다!! 18432KB 200ms Java 2633B
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {

	static int n,m;
	static int[][] board;
	static int[][] tb;
	static int cctv=0;
	static int[][] info=new int[8][3];
	static int[] pos=new int[8];
	static int black=64;
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		int i,j;
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());

		board = new int[n][m];
		tb = new int[n][m];
		
		for(i=0;i<n;i++) {
			st = new StringTokenizer(br.readLine());
			for(j=0;j<m;j++) {
				board[i][j]=Integer.parseInt(st.nextToken());
				if(board[i][j]>0&&board[i][j]<6) {
					info[cctv][0]=i;
					info[cctv][1]=j;
					info[cctv][2]=board[i][j];
					cctv++;
				}
			}
		}
		dfs(0);
		bw.write(black+"\n");
		br.close();
		bw.close();
	}
	static void dfs(int k) {
		if(k==cctv) {//cctv를 다 설치했다면
			for(int i=0;i<n;i++) {//배열복사
				System.arraycopy(board[i], 0, tb[i], 0, m);
			}

			for(int i=0;i<cctv;i++) {
				int r=pos[i];
                //위쪽 검사
				if(r%2==1) {
					int y=info[i][0]-1;
					int x=info[i][1];
					while(true) {
						if(y<0||tb[y][x]==6) break;
						tb[y--][x]=1;
					}
				}
				r>>=1;
                //오른쪽 검사
				if(r%2==1) {
					int y=info[i][0];
					int x=info[i][1]+1;
					while(true) {
						if(x>=m||tb[y][x]==6) break;
						tb[y][x++]=1;
					}
				}
				r>>=1;
                //아래쪽 검사
				if(r%2==1) {
					int y=info[i][0]+1;
					int x=info[i][1];
					while(true) {
						if(y>=n||tb[y][x]==6) break;
						tb[y++][x]=1;
					}
				}
				r>>=1;
                //왼쪽 검사
				if(r%2==1) {
					int y=info[i][0];
					int x=info[i][1]-1;
					while(true) {
						if(x<0||tb[y][x]==6) break;
						tb[y][x--]=1;
					}
				}
			}
			int cnt = 0;
			for(int p=0;p<n;p++) {
				for(int q=0;q<m;q++) {
					if(tb[p][q]==0) cnt++;
				}
			}
			black = Math.min(black, cnt);
			return;
		}
		switch(info[k][2]) {//감시탑 번호
        // 감시는 2진법을 이용해
        // 0001(2)=1 위
        // 0010(2)=2 오른쪽
        // 0100(2)=4 아래
        // 1000(2)=8 왼쪽
		case 1:
			pos[k]=1;//위 
			dfs(k+1);
			pos[k]=2;//오른쪽
			dfs(k+1);
			pos[k]=4;//아래
			dfs(k+1);
			pos[k]=8;//왼쪽
			dfs(k+1);
			break;
		case 2:
			pos[k]=5;//위+아래
			dfs(k+1);
			pos[k]=10;//오른쪽+왼쪽
			dfs(k+1);
			break;
		case 3:
			pos[k]=3;
			dfs(k+1);
			pos[k]=6;
			dfs(k+1);
			pos[k]=12;
			dfs(k+1);
			pos[k]=9;
			dfs(k+1);
			break;
		case 4:
			pos[k]=7;
			dfs(k+1);
			pos[k]=14;
			dfs(k+1);
			pos[k]=13;
			dfs(k+1);
			pos[k]=11;
			dfs(k+1);
			break;
		case 5:
			pos[k]=15;
			dfs(k+1);
		}
	}
}

바뀐 점1

StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());

을 사용 하면 더이상 split을 하지 않고 사용해도 된다 split의 경우 정규식을 사용할 수 있는 장점이 있지만 느림

 

바뀐 점2

r/=2를 사용하지 않고 쉬프트연산을 사용하면 미세하게 빨라진 다는 것을 알 수 있었음

 

바뀐 점3

println을 사용하지 않고 write함수를 사용해 출력하면 미세하게 빨라짐

 

바뀐 점4

숫자가 많은 if else문을 사용할 경우 swtich문이 좀 더 효율 적이다.

 

 

 

JAVA - 수정 전

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16374521 cbkpar 15683 맞았습니다!! 18892KB 200ms Java 2354B
import java.io.*;

public class Main {

	static int n,m;
	static int[][] board;
	static int[][] tb;
	static int cctv=0;
	static int[][] info=new int[8][3];
	static int[] pos=new int[8];
	static int black=64;
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int i,j;
		
		String str = "";
		str = br.readLine();
		String[] arr = str.split(" ");
		n = Integer.parseInt(arr[0]);
		m = Integer.parseInt(arr[1]);

		board = new int[n][m];
		tb = new int[n][m];
		
		for(i=0;i<n;i++) {
			str = br.readLine();
			arr = str.split(" ");
			for(j=0;j<m;j++) {
				board[i][j]=Integer.parseInt(arr[j]);
				if(board[i][j]>0&&board[i][j]<6) {
					info[cctv][0]=i;
					info[cctv][1]=j;
					info[cctv][2]=board[i][j];
					cctv++;
				}
			}
		}
		dfs(0);
		System.out.println(black);
	}
	static void dfs(int k) {
		if(k==cctv) {
			for(int i=0;i<n;i++) {
				System.arraycopy(board[i], 0, tb[i], 0, m);
			}

			for(int i=0;i<cctv;i++) {
				int r=pos[i];
				if(r%2==1) {
					int y=info[i][0]-1;
					int x=info[i][1];
					while(true) {
						if(y<0||tb[y][x]==6) break;
						tb[y--][x]=1;
					}
				}
				r/=2;
				if(r%2==1) {
					int y=info[i][0];
					int x=info[i][1]+1;
					while(true) {
						if(x>=m||tb[y][x]==6) break;
						tb[y][x++]=1;
					}
				}
				r/=2;
				if(r%2==1) {
					int y=info[i][0]+1;
					int x=info[i][1];
					while(true) {
						if(y>=n||tb[y][x]==6) break;
						tb[y++][x]=1;
					}
				}
				r/=2;
				if(r%2==1) {
					int y=info[i][0];
					int x=info[i][1]-1;
					while(true) {
						if(x<0||tb[y][x]==6) break;
						tb[y][x--]=1;
					}
				}
			}
			int cnt = 0;
			for(int p=0;p<n;p++) {
				for(int q=0;q<m;q++) {
					if(tb[p][q]==0) cnt++;
				}
			}
			black = Math.min(black, cnt);
			return;
		}
		if(info[k][2]==1) {
			pos[k]=1;
			dfs(k+1);
			pos[k]=2;
			dfs(k+1);
			pos[k]=4;
			dfs(k+1);
			pos[k]=8;
			dfs(k+1);
		}else if(info[k][2]==2) {
			pos[k]=5;
			dfs(k+1);
			pos[k]=10;
			dfs(k+1);
		}else if(info[k][2]==3) {
			pos[k]=3;
			dfs(k+1);
			pos[k]=6;
			dfs(k+1);
			pos[k]=12;
			dfs(k+1);
			pos[k]=9;
			dfs(k+1);
		}else if(info[k][2]==4) {
			pos[k]=7;
			dfs(k+1);
			pos[k]=14;
			dfs(k+1);
			pos[k]=13;
			dfs(k+1);
			pos[k]=11;
			dfs(k+1);
		}else {
			pos[k]=15;
			dfs(k+1);
		}
	}
}

 

 

JAVA - Byte변환 후

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16380074 cbkpar 15683 맞았습니다!! 17744KB 236ms Java 2694B
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {

	static byte n,m;
	static byte[][] board;
	static byte[][] tb;
	static byte cctv=0;
	static byte[][] info=new byte[8][3];
	static byte[] pos=new byte[8];
	static byte black=64;
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		byte i,j;
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		n = Byte.parseByte(st.nextToken());
		m = Byte.parseByte(st.nextToken());

		board = new byte[n][m];
		tb = new byte[n][m];
		
		for(i=0;i<n;i++) {
			st = new StringTokenizer(br.readLine());
			for(j=0;j<m;j++) {
				board[i][j]=Byte.parseByte(st.nextToken());
				if(board[i][j]>0&&board[i][j]<6) {
					info[cctv][0]=i;
					info[cctv][1]=j;
					info[cctv][2]=board[i][j];
					cctv++;
				}
			}
		}
		dfs(0);
		bw.write(black+"\n");
		br.close();
		bw.close();
	}
	static void dfs(int k) {
		if(k==cctv) {
			for(byte i=0;i<n;i++) {
				System.arraycopy(board[i], 0, tb[i], 0, m);
			}

			for(byte i=0;i<cctv;i++) {
				byte r=pos[i];
				if(r%2==1) {
					byte y=(byte) (info[i][0]-1);
					byte x=info[i][1];
					while(true) {
						if(y<0||tb[y][x]==6) break;
						tb[y--][x]=1;
					}
				}
				r>>=1;
				if(r%2==1) {
					byte y=info[i][0];
					byte x=(byte) (info[i][1]+1);
					while(true) {
						if(x>=m||tb[y][x]==6) break;
						tb[y][x++]=1;
					}
				}
				r>>=1;
				if(r%2==1) {
					byte y=(byte) (info[i][0]+1);
					byte x=info[i][1];
					while(true) {
						if(y>=n||tb[y][x]==6) break;
						tb[y++][x]=1;
					}
				}
				r>>=1;
				if(r%2==1) {
					byte y=info[i][0];
					byte x=(byte) (info[i][1]-1);
					while(true) {
						if(x<0||tb[y][x]==6) break;
						tb[y][x--]=1;
					}
				}
			}
			byte cnt = 0;
			for(int p=0;p<n;p++) {
				for(int q=0;q<m;q++) {
					if(tb[p][q]==0) cnt++;
				}
			}
			black = (byte) Math.min(black, cnt);
			return;
		}
		switch(info[k][2]) {
		case 1:
			pos[k]=1;
			dfs(k+1);
			pos[k]=2;
			dfs(k+1);
			pos[k]=4;
			dfs(k+1);
			pos[k]=8;
			dfs(k+1);
			break;
		case 2:
			pos[k]=5;
			dfs(k+1);
			pos[k]=10;
			dfs(k+1);
			break;
		case 3:
			pos[k]=3;
			dfs(k+1);
			pos[k]=6;
			dfs(k+1);
			pos[k]=12;
			dfs(k+1);
			pos[k]=9;
			dfs(k+1);
			break;
		case 4:
			pos[k]=7;
			dfs(k+1);
			pos[k]=14;
			dfs(k+1);
			pos[k]=13;
			dfs(k+1);
			pos[k]=11;
			dfs(k+1);
			break;
		case 5:
			pos[k]=15;
			dfs(k+1);
		}
	}
}

Byte로 변환한 결과 메모리사용은 적어졌지만 수행하는 시간은 길어진 것을 알 수 있었음

문제 : https://www.acmicpc.net/problem/14891

 

14891번: 톱니바퀴

첫째 줄에 1번 톱니바퀴의 상태, 둘째 줄에 2번 톱니바퀴의 상태, 셋째 줄에 3번 톱니바퀴의 상태, 넷째 줄에 4번 톱니바퀴의 상태가 주어진다. 상태는 8개의 정수로 이루어져 있고, 12시방향부터 시계방향 순서대로 주어진다. N극은 0, S극은 1로 나타나있다. 다섯째 줄에는 회전 횟수 K(1 ≤ K ≤ 100)가 주어진다. 다음 K개 줄에는 회전시킨 방법이 순서대로 주어진다. 각 방법은 두 개의 정수로 이루어져 있고, 첫 번째 정수는 회전시킨 톱니바퀴

www.acmicpc.net

 

문제 요약 : 톱니바퀴를 회전 시킨 후 점수 계산

입력 출력

N[4][8](톱니) = 0(N), 1(S)

1 ≤ K(회전수) ≤ 100

K줄 : (톱니번호(1~4)) (회전=1(R),-1(L))

점수 출력

1번톱니 S극이면 1점 추가

2번톱니 S극이면 2점 추가

3번톱니 S극이면 4점 추가

4번톱니 S극이면 8점 추가

 

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16373307 cbkpar 14891 맞았습니다!! 12972KB 76ms Java 1850B
import java.io.*;

public class Main {
	static int[][] gear = new int[4][8];

	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n,i,j,grn,grr;
		String str = "";
		
		for(i=0;i<4;i++) {
			str = br.readLine();
			for(j=0;j<8;j++) {
				gear[i][j] = str.charAt(j) - '0'; //문자형으로 받았기 때문에 숫자로 변환
			}
		}
		n = Integer.parseInt(br.readLine());
		for(i=0;i<n;i++) {
			str = br.readLine();
			String[] arr = str.split(" ");
			grn = Integer.parseInt(arr[0])-1;
			grr = Integer.parseInt(arr[1]);
			lrotate(grn,grr,1); // 왼쪽으로 확인하면서 회전
			rrotate(grn,grr,1); // 오른쪽으로 확인하면서 회전
			if(grr==1) { //회전방향이 시계방향이라면
            //배열을 오른쪽으로 미는 과정
				int tmp = gear[grn][7]; 
				for(j=7;j>0;j--) {
					gear[grn][j]=gear[grn][j-1];
				}
				gear[grn][0]=tmp;
			}else { //회전방향이 반시계방향이라면
            //배열을 왼쪽으로 미는 과정
				int tmp = gear[grn][0];
				for(j=0;j<7;j++) {
					gear[grn][j]=gear[grn][j+1];
				}
				gear[grn][7]=tmp;
			}
		}
        //점수계산
		int score = 0;
		if(gear[0][0]==1) score+=1;
		if(gear[1][0]==1) score+=2;
		if(gear[2][0]==1) score+=4;
		if(gear[3][0]==1) score+=8;
		System.out.println(score);
	}
	static void lrotate(int gn, int gr, int st) {
		if(gn<0) return; // 확인할 톱니가 없다면 리턴
		if(gn>=1&&gear[gn-1][2]!=gear[gn][6]) { //왼쪽톱니와 극이 다르다면
			lrotate(gn-1,gr*-1,0); // 왼쪽으로 한번더가면서 확인
		}
		if(st==1) return; // 첫번째 톱니라면 종료->메인함수에서 회전
        //회전
		if(gr==1) {
			int tmp = gear[gn][7];
			for(int i=7;i>0;i--) {
				gear[gn][i]=gear[gn][i-1];
			}
			gear[gn][0]=tmp;
		}else {
			int tmp = gear[gn][0];
			for(int i=0;i<7;i++) {
				gear[gn][i]=gear[gn][i+1];
			}
			gear[gn][7]=tmp;
		}
	}
    //오른쪽방향으로 확인
	static void rrotate(int gn, int gr, int st) {
		if(gn>3) return;
		if(gn<=2&&gear[gn+1][6]!=gear[gn][2]) {
			rrotate(gn+1,gr*-1,0);
		}
		if(st==1) return;
		if(gr==1) {
			int tmp = gear[gn][7];
			for(int i=7;i>0;i--) {
				gear[gn][i]=gear[gn][i-1];
			}
			gear[gn][0]=tmp;
		}else {
			int tmp = gear[gn][0];
			for(int i=0;i<7;i++) {
				gear[gn][i]=gear[gn][i+1];
			}
			gear[gn][7]=tmp;
		}
	}
}

 

JAVA - 회전부분을 함수화[속도 느려짐]

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16373910 cbkpar 14891 맞았습니다!! 12948KB 88ms Java 1239B
import java.io.*;

public class Main {
	static int[][] gear = new int[4][8];

	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n,i,j,grn,grr;
		String str = "";
		
		for(i=0;i<4;i++) {
			str = br.readLine();
			for(j=0;j<8;j++) {
				gear[i][j] = str.charAt(j) - '0';
			}
		}
		n = Integer.parseInt(br.readLine());
		for(i=0;i<n;i++) {
			str = br.readLine();
			String[] arr = str.split(" ");
			grn = Integer.parseInt(arr[0])-1;
			grr = Integer.parseInt(arr[1]);
			lcheck(grn,grr,1);
			rcheck(grn,grr,1);
			rotate(grn,grr);
		}
		int score = 0;
		for(i=3;i>=0;i--) {
			score*=2;
			if(gear[i][0]==1) score++;
		}
		System.out.println(score);
	}
	static void lcheck(int gn, int gr, int st) {
		if(gn<0) return;
		if(gn>=1&&gear[gn-1][2]!=gear[gn][6]) lcheck(gn-1,gr*-1,0);
		if(st!=1) rotate(gn,gr);
	}
	static void rcheck(int gn, int gr, int st) {
		if(gn>3) return;
		if(gn<=2&&gear[gn+1][6]!=gear[gn][2]) rcheck(gn+1,gr*-1,0);
		if(st!=1) rotate(gn,gr);
	}
	static void rotate(int gn, int gr) {
		int tn = (8-gr)%9;
		int tmp = gear[gn][tn];
		for(int i=0;i<7;i++) gear[gn][tn-gr*i]=gear[gn][tn-gr*(i+1)];
		gear[gn][7-tn]=tmp;
	}		
}

문제 : https://www.acmicpc.net/problem/14890

 

14890번: 경사로

첫째 줄에 N (2 ≤ N ≤ 100)과 L (1 ≤ L ≤ N)이 주어진다. 둘째 줄부터 N개의 줄에 지도가 주어진다. 각 칸의 높이는 10보다 작거나 같은 자연수이다.

www.acmicpc.net

문제 요약 : 지도에서 경사로를 사용해 지나갈 수 있는 길의 개수 출력

입력 출력

2 ≤ N(크기) ≤ 100

1 ≤ [N][N](높이) ≤ 10

1 ≤ L(경사로길이) ≤ N

경사로를 이용해 갈 수 있는 길의 개수

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16366827 cbkpar 14890 맞았습니다!! 14060KB 96ms Java 1692B
import java.io.*;

public class Main {

	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n,l,i,j;
		String str = "";
		str = br.readLine();
		String[] arr = str.split(" ");
		n = Integer.parseInt(arr[0]);
		l = Integer.parseInt(arr[1]);
		
		int[][] map = new int[n][n];
		for(i=0;i<n;i++) {
			str = br.readLine();
			arr = str.split(" ");
			for(j=0;j<n;j++) {
				map[i][j] = Integer.parseInt(arr[j]);
			}
		}
		
		int path = 0;
        //왼쪽 위에서 아래 순서로 왼쪽에서 오른쪽으로 갈 수 있는지 확인
		for(i=0;i<n;i++) {
			int p = 1; //0번은 검사할 필요 없기 때문에 1번부터 검사
			int q = map[i][0]; // 저장된 높이
			int r = 1; // 검사해온곳까지 경사로를 놓을 수 있는 길이
			while(p<n) {
				if(map[i][p]==q) { // 높이가 같다면
					p++; // 다음블럭 검사
					r++; // 경사로 놓을 수 있는 길이 1증가
					continue;
				}else if(map[i][p]==q+1) { //블럭이 현재까지 검사해온 블럭보다 1칸 높다면
					if(r<l) break; // 블럭을 놓을 수 없으면 종료
					q=map[i][p]; // 저장해온 블럭 높이 수정
					r=1; // 놓을 수 있는 경사로 길이 1로 수정
					p++; // 다음 블럭 검사
					continue;
				}else if(map[i][p]==q-1) { //블럭이 현재까지 검사해온 블럭보다 1칸 낮다면
					int tmppath=1; // 경사로를 놓을 수 있는지 확인 초기 1칸
					for(j=1;j<l;j++) {
						if(p+j>=n) break; // 지도 범위보다 초과하면 종료
						if(map[i][p]!=map[i][p+j]) break; //높이가 다르다면 종료
						if(map[i][p]==map[i][p+j]) tmppath++; // 높이가 같으면 1칸 증가
					}
					if(tmppath<l) break; // 경사로를 놓을 수 없다면 종료
					p+=l; //경사로를 놓은 후 l블럭 다음부터 검사
					q=map[i][p-1];
					r=0; // 내려왔기때문에 그자리에 블럭을 놓을 수 없어서 경사로 길이0으로 초기화
					continue;
				}
				break;
			}
			if(p==n) path++; // 끝까지 건너 왔다면 길을 1개 증가
		}
        //위 왼쪽에서 오른쪽 순서로 위에서 아래로 갈 수 있는지 확인
        for(i=0;i<n;i++) {
			int p = 1;
			int q = map[0][i];
			int r = 1;
			while(p<n) {
				if(map[p][i]==q) {
					p++;
					r++;
					continue;
				}else if(map[p][i]==q+1) {
					if(r<l) break;
					q=map[p][i];
					r=1;
					p++;
					continue;
				}else if(map[p][i]==q-1) {
					int tmppath=1;
					for(j=1;j<l;j++) {
						if(p+j>=n) break;
						if(map[p][i]!=map[p+j][i]) break;
						if(map[p][i]==map[p+j][i]) tmppath++;
					}
					if(tmppath<l) break;
					p+=l;
					q=map[p-1][i];
					r=0;
					continue;
				}
				break;
			}
			if(p==n) path++;
		}
		System.out.println(path); // 가능한 길의 개수 출력
	}
}

문제 : https://www.acmicpc.net/problem/14503

 

14503번: 로봇 청소기

로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오. 로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 벽 또는 빈 칸이다. 청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북중 하나이다. 지도의 각 칸은 (r, c)로 나타낼 수 있고, r은 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로 부터 떨어진 칸의 개수이다. 로봇 청소기는 다음

www.acmicpc.net

문제 요약 : 로봇이 청소하는 칸 수 출력

입력 출력

3 ≤ N,M(크기) ≤ 50

1 ≤ R < N

1 ≤ C <M

d = 0(북), 1(동), 2(남), 3(서)

[N][M] = 0(빈 칸), 1(벽)

로봇이 청소하는 칸 수 출력

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16356986 cbkpar 14503 맞았습니다!! 13292KB 76ms Java 1367B
import java.io.*;

public class Main {

	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int[] dx = {0,1,0,-1}; // 북동남서
		int[] dy = {-1,0,1,0};
		int n,m,y,x,d,i,j;
		String str = "";
		str = br.readLine();
		String[] arr = str.split(" ");
		n = Integer.parseInt(arr[0]);
		m = Integer.parseInt(arr[1]);
		
		str = br.readLine();
		arr = str.split(" ");
		y = Integer.parseInt(arr[0]);
		x = Integer.parseInt(arr[1]);
		d = Integer.parseInt(arr[2]);
		int[][] map = new int[n][m];
		for(i=0;i<n;i++) {
			str = br.readLine();
			arr = str.split(" ");
			for(j=0;j<m;j++) {
				map[i][j] = Integer.parseInt(arr[j]);
			}
		}
		int clean = 0;
		while(true) {
			if(map[y][x]==0) { //청소가능 여부
				map[y][x]=2;
				clean++;
			}
            //왼쪽으로 돌아가면서 청소가 가능한지 확인
			if(map[y+dy[(d+3)%4]][x+dx[(d+3)%4]]==0) {
				d=(d+3)%4;
				y+=dy[d];
				x+=dx[d];
				continue;
			}
			if(map[y+dy[(d+2)%4]][x+dx[(d+2)%4]]==0) {
				d=(d+2)%4;
				y+=dy[d];
				x+=dx[d];
				continue;
			}
			if(map[y+dy[(d+1)%4]][x+dx[(d+1)%4]]==0) {
				d=(d+1)%4;
				y+=dy[d];
				x+=dx[d];
				continue;
			}
			if(map[y+dy[d]][x+dx[d]]==0) {
				y+=dy[d];
				x+=dx[d];
				continue;
			}
            
            //4방향 청소가 불가능 하다면
			if(map[y+dy[(d+2)%4]][x+dx[(d+2)%4]]==1) {
				break; //뒤에 벽이 있으면 종료
			}else {
            //벽이 없을경우 후진
				y+=dy[(d+2)%4];
				x+=dx[(d+2)%4];
				continue;
			}
		}
		System.out.println(clean);
	}
}

 

문제 : https://www.acmicpc.net/problem/14502

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다.  일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다.

www.acmicpc.net

문제 요약 : 벽을 3개 세워 만들 수 있는 안전한 공간의 최대 크기

입력 출력

3 ≤ N,M(크기) ≤ 8

[N][M] = 0(빈 칸), 1(벽), 2(가스)

벽을 3개 세운 후 안전한 공간의 최대 크기

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어  코드 길이
16355178 cbkpar 14502 맞았습니다!! 15980KB 160ms Java 1596B
import java.io.*;

public class Main {
	static int n,m;
	static int[][] map;
	static int[][] test;
	static int[][] gas_loc = new int[10][2];
	static int ngas=0;
	static int safe=0;

	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int i,j;
		String str = "";
		str = br.readLine();
		String[] arr = str.split(" ");
		n = Integer.parseInt(arr[0]);
		m = Integer.parseInt(arr[1]);
		map = new int[n][m];
		test = new int[n][m];
		for(i=0;i<n;i++) {
			str = br.readLine();
			arr = str.split(" ");
			for(j=0;j<m;j++) {
				map[i][j] = Integer.parseInt(arr[j]);
				if(map[i][j]==2) {//가스라면 위치저장
					gas_loc[ngas][0]=i;
					gas_loc[ngas][1]=j;
					ngas++;
				}
			}
		}
		wall(0,0);
		System.out.println(safe);
	}
	static void wall(int w, int k) {
		if(k==3) {//벽이 3개라면
			for(int i=0;i<n;i++) {
				System.arraycopy(map[i], 0, test[i], 0, m); // 배열복사
			}
			for(int i=0;i<ngas;i++) {
				gas(gas_loc[i][0],gas_loc[i][1]); // 저장된 가스 위치에서 가스 확산
			}
			int safecnt = 0;
            //안전구역 개수 계산
			for(int i=0;i<n;i++) {
				for(int j=0;j<m;j++) {
					if(test[i][j]==0) safecnt++;
				}
			}
			safe = Math.max(safe, safecnt);
			return;
		}
		for(int i=w;i<n*m;i++) {//왼쪽에서 오른쪽, 위에서 아래 순으로 벽을 세움
			if(map[i/m][i%m]==0) {//벽을 세울 수 있다면
				map[i/m][i%m]=1;
				wall(i+1,k+1);
				map[i/m][i%m]=0;
			}
		}
	}
	static void gas(int y, int x) {
    //가스 확산
		if(y>0&&test[y-1][x]==0) {//상
			test[y-1][x]=2;
			gas(y-1,x);
		}
		if(y<n-1&&test[y+1][x]==0) {//하
			test[y+1][x]=2;
			gas(y+1,x);
		}
		if(x>0&&test[y][x-1]==0) {//좌
			test[y][x-1]=2;
			gas(y,x-1);
		}
		if(x<m-1&&test[y][x+1]==0) {//우
			test[y][x+1]=2;
			gas(y,x+1);
		}
	}
}

문제 : https://www.acmicpc.net/problem/14501

 

14501번: 퇴사

첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.

www.acmicpc.net

 

문제 요약 : 최대 이익 계산

입력 출력

1 ≤ N(일) ≤ 15

1 ≤ T(소요일) ≤ 5

1 ≤ P(이익) ≤ 1000

최대 이익

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16353541 cbkpar 14501 맞았습니다!! 12908KB 72ms Java 639B
import java.io.*;

public class Main {

	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n,i;
		String str = "";
		n = Integer.parseInt(br.readLine());
		int[] dp = new int[n+1];
		int[] t = new int[n];
		int[] p = new int[n];
		for(i=0;i<n;i++) {
			str = br.readLine();
			String[] arr = str.split(" ");
			t[i]=Integer.parseInt(arr[0]);
			p[i]=Integer.parseInt(arr[1]);
		}
		for(i=1;i<=n;i++) {
        //이익을 첫날부터계산하지 않고 N일부터 거꾸로 계산함
			dp[i]=Math.max(dp[i], dp[i-1]);//그 날 얻을 수 있는 이익은 그 전날 이익보다 크거나 같음
			if(t[n-i]>i) continue; // 퇴사일 보다 넘어가면 무시
			dp[i]=Math.max(dp[i], dp[i-t[n-i]]+p[n-i]); // 그날의 최댓값과 그전날의 최댓값+이익 중 큰 값으로 교체
		}
		System.out.println(dp[n]);
	}
}

예시[입력]

10

5 50

4 40

3 30

2 20

1 10

1 10

2 20

3 30

4 40

5 50

 

과정[출력]

0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 30 0 0 0 0 0 0 0
0 0 0 30 30 0 0 0 0 0 0
0 0 0 30 30 40 0 0 0 0 0
0 0 0 30 30 40 50 0 0 0 0
0 0 0 30 30 40 50 60 0 0 0
0 0 0 30 30 40 50 60 70 0 0
0 0 0 30 30 40 50 60 70 80 0
0 0 0 30 30 40 50 60 70 80 90

 

 

오답노트 : dp[i]=Math.max(dp[i], dp[i-1]); 을 써주지 않으면 조건에 만족하지 않을경우 그날의 최댓값을 알 수 없다.

문제 : https://www.acmicpc.net/problem/14500

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다. 정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다. 아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누

www.acmicpc.net

 

문제요약 : 이어지는 4개의 정사각형 구간합의 최댓값 출력

입력 출력

4 ≤ N,M(크기) ≤ 500

1 ≤ [N][M] ≤ 1000

테트로미노가 놓인 칸의 합의 최댓값

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16352773 cbkpar 14500 맞았습니다!! 38684KB 668ms Java 1199B
import java.io.*;

public class Main {

	static int[][] map;
	static int[][] move;
	static int n,m;
	static int score=0;
	static int[] dx = {0,0,1,-1}; //상하우좌
	static int[] dy = {1,-1,0,0};
	
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int i,j;
		String str = "";
		str = br.readLine();
		String[] arr = str.split(" ");
		n = Integer.parseInt(arr[0]);
		m = Integer.parseInt(arr[1]);
		map = new int[n][m];
		move = new int[n][m];
		for(i=0;i<n;i++) {
			str = br.readLine();
			arr = str.split(" ");
			for(j=0;j<m;j++) {
				map[i][j] = Integer.parseInt(arr[j]);
			}
		}
		for(i=0;i<n;i++) {
			for(j=0;j<m;j++) {
				move[i][j]=1; // 해당구간 이동 불가 설정
				dfs(i,j,map[i][j],1);
				move[i][j]=0; // 해당구간 이동 가능 설정
			}
		}
		System.out.println(score);
	}

	static void dfs(int y, int x, int s, int k) {
		if(k==4) { // 4개의 정사각형 선택했을 경우
			score = Math.max(score, s); // 최대값 갱신 후 리턴
			return;
		}
		for(int i=0;i<4;i++) {
			if(y+dy[i]>=0&&y+dy[i]<n&&x+dx[i]>=0&&x+dx[i]<m&&move[y+dy[i]][x+dx[i]]==0) {
            //인덱스를 넘어가거나 이동이 가능한지 확인
				move[y+dy[i]][x+dx[i]]=1; //가능하다면 이동불가상태로 만듦
				dfs(y+dy[i],x+dx[i],s+map[y+dy[i]][x+dx[i]],k+1);
				if(k==2) dfs(y,x,s+map[y+dy[i]][x+dx[i]],k+1); // 2번째 블럭의 경우 2번째 블럭에서 다시체크
				move[y+dy[i]][x+dx[i]]=0; //다시 이동 가능하도록 설정
			}
		}
	}
}

 

JAVA - 배열을 쓰지 않고 상하좌우를 나눴을 때

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16352586 cbkpar 14500 맞았습니다!! 37348KB 568ms Java 1438B
import java.io.*;

public class Main {

	static int[][] map;
	static int[][] move;
	static int n,m;
	static int score=0;
	
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int i,j;
		String str = "";
		str = br.readLine();
		String[] arr = str.split(" ");
		n = Integer.parseInt(arr[0]);
		m = Integer.parseInt(arr[1]);
		map = new int[n][m];
		move = new int[n][m];
		for(i=0;i<n;i++) {
			str = br.readLine();
			arr = str.split(" ");
			for(j=0;j<m;j++) {
				map[i][j] = Integer.parseInt(arr[j]);
			}
		}
		for(i=0;i<n;i++) {
			for(j=0;j<m;j++) {
				move[i][j]=1;
				dfs(i,j,map[i][j],1);
				move[i][j]=0;
			}
		}
		System.out.println(score);
	}

	static void dfs(int y, int x, int s, int k) {
		if(k==4) {
			score = Math.max(score, s);
			return;
		}
		if(y>0&&move[y-1][x]==0) {
			move[y-1][x]=1;
			dfs(y-1,x,s+map[y-1][x],k+1);
			if(k==2) dfs(y,x,s+map[y-1][x],k+1);
			move[y-1][x]=0;
		}
		if(y<n-1&&move[y+1][x]==0) {
			move[y+1][x]=1;
			dfs(y+1,x,s+map[y+1][x],k+1);
			if(k==2) dfs(y,x,s+map[y+1][x],k+1);
			move[y+1][x]=0;
		}
		if(x>0&&move[y][x-1]==0) {
			move[y][x-1]=1;
			dfs(y,x-1,s+map[y][x-1],k+1);
			if(k==2) dfs(y,x,s+map[y][x-1],k+1);
			move[y][x-1]=0;
		}
		if(x<m-1&&move[y][x+1]==0) {
			move[y][x+1]=1;
			dfs(y,x+1,s+map[y][x+1],k+1);
			if(k==2) dfs(y,x,s+map[y][x+1],k+1);
			move[y][x+1]=0;
		}
	}
}

 

배열을 쓰지 않고 if문으로 상하좌우를 나눴을 때 시간을 단축 할 수 있었음.

 

개선할 점 : 한 블럭에 대해서 중복해서 검사하는 회수가 적어도 2회 이상이므로 중복을 제거하면 시간을 2배이상 단축 할 수 있을 것으로 예상.

 

아래는 중복검사하는 과정(숫자는 순서)

1   4   1 4   4 3
2   3   2 3   1 2
3   2            
4   1   3 2   2 1
        4 1   3 4

 

+ Recent posts