[풀이]백준 풀이(VI/16929), SW EA(1767)
문제풀이
[RE]Two Dots(16929, DFS, O(N*M))
- 사이클의 정의 (같은 색, 4개 이상 연결된 점들의 집합)
- 즉, 임의의 점에서 시작해서 길이가 4이상인 도착점(자기자신)이 있는지만 확인.
- DFS, BFS 모두 가능.
풀이1. 마지막 정점에서 find를 한 뒤 이미 방문했던 같은 색상의 점이 있다면 사이클이 존재. (일단 갔던 곳도 방문을 해 본 뒤, 뺄셈)
풀이2. 이전 칸과 다른 칸만 방문해서 이미 방문했던 곳으로 돌아오게 될 경우 사이클은 무조건 존재한다.
TIP: 다른 점에서 DFS를 다시 시작 할 경우 CHECK배열을 초기화할 필요가 없다.(사이클이 있었으면 이미 끝났고 다시 본다고 해도 사이클이 생기지도 않음).
회고
- 좀 다른 방식으로 푼 것 같다.
- 수업 내용 중
중복을 줄이기 위해 이미 갔던곳은 반복하지 않는 경우가 있었던 것이 기억나 memset을 안해서 답이 틀렸었다.
YYYR
BYBY
BBBY
BBBY
의 경우 (1,0)의 B에서 시작하면 마지막 조건문 sx==cx && sy==cy에 걸리지 않고 다른 점들을 모두 방문한 노드로 변경해버렸었다..
디버깅은 참 좋은 기능이다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m, sx, sy;
bool check[51][51];
char map[51][51];
bool fin;
int dx[] = {0, 0, 1, -1 };
int dy[] = {1, -1, 0, 0 };
void dfs(int x, int y, char color, int count){
if(fin) return;
for(int i=0; i<4; i++){
int cx = x + dx[i];
int cy = y + dy[i];
if(cx>=0 && cx<n && cy>=0 && cy<m)
{
if(!check[cx][cy])
{
if(map[cx][cy] == color)
{
check[cx][cy] = true;
dfs(cx,cy, color, count+1);
}
}
else
{
if(count >=4 && sx == cx && sy ==cy)
{
fin = true;
return;
}
}
}
}
}
int main(){
cin >> n >> m;
//입력
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
char a;
cin >> a;
map[i][j] = a;
}
}
//dfs 실행
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
memset(check, false, sizeof(check));
sx = i; sy = j;
check[i][j]=true;
int cnt =1;
dfs(i,j, map[i][j], cnt);
if(fin)
{
cout<<"Yes"<<endl;
return 0;
}
}
}
cout << "No" << endl;
return 0;
}
[RE] 프로세서 연결하기 (SW 아카데미)
- N * N 의 행렬 (CORE 혹은 전선이 들어갈 수 있다.)
- (7<=N<=12), (1<=num of CORE<=12), 연결되지 않는 코어 허용
- 행렬의 가장자리에는 전원이 흐르고 있다. (가장자리에 위치한 코어는 전선이 필요없다.)
- core와 전원을 연결하는 전선은 직석으로만 설치가 가능하다.
- 전원은 교차할 수 없다.
- 최대한 많은 Core에 전원을 연결한 경우 전선 길이의 합은? (같은 Core 개수가 있다면 전선길이가 최소인 것을 출력)
방법 생각하기
- Core의 개수가 주어지므로 각 코어에서 DFS를 돌리면 될 것 같은데..
- 순차적으로 DFS/BFS를 진행하며 지나갔던 길은
CHECK한다. - 문제는 DFS, BFS의 목적지 NODE를 무엇으로 하느냐 인 것 같다.
풀이 1. 선택한
1에서 갈 수 있는 모든 모서리를 다 본다.
N의 최대가 12이므로 4^12 = 2^24 = 16777216(2천만) 타임아웃이 안난다.
- 가장자리 코어는 따로 카운트
- 나머지 코어에 들은
DFS부분부터 다시짜기
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>
#define INF 987654321
using namespace std;
int N, Answer=INF, nx, ny;
bool check[13][13];
int map[13][13], dist[13];
char direction[4] = { 'U', 'D', 'L', 'R' };
vector<pair<int, int>> core;
bool isConnection(int x, int y, char direction) {
if (direction == 'D' )
{
for (int j = x + 1; j < N; j++) {
if (map[j][y]) return false;
}
//위쪽에 갈 수 있는 길이 있다. - 지나간다
for (int j = x + 1; j < N; j++) {
map[j][y] = 2;
}
return true;
}
if (direction == 'U')
{
for (int j = x - 1; j >= 0; j--) {
if (map[j][y]) return false;
}
for (int j = x - 1; j >= 0; j--) {
map[j][y] = 2;
}
return true;
}
if (direction == 'R')
{
for (int j = y + 1; j < N; j++) {
if (map[x][j]) return false;
}
for (int j = y + 1; j < N; j++) {
map[x][j] = 2;
}
return true;
}
if (direction == 'L')
{
for (int j = x; j < N; j++) {
if (map[j][y]) return false;
}
for (int j = x; j < N; j++) {
map[x][j] = 2;
}
return true;
}
}
bool isEdge(int x, int y) {
if (x == 0 || x == N - 1 || y == 0 || y == N - 1) return true;
else return false;
}
void init() {
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
map[j][k] = 0;
check[j][k] = false;
}
}
}
int calcDist() {
int dist = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j] == 2) dist++;
}
}
return dist;
}
bool find_next(int x, int y) {
for (int i = 0; i < core.size(); i++) {
if (core[i].first == x && core[i].second==y) {
if (i == core.size() - 1)
{
Answer = min(Answer, calcDist());
return false;
}
nx = core[i + 1].first;
ny = core[i + 1].second;
return true;
}
}
}
void dfs(int x, int y) {
//if(조건을 만족하면) 종료
//전선은 오직 직선, 4방향 모두 확인
for (int i = 0; i < 4; i++) {
//예외1. 현재 위치(x,y)가 가장자리인 경우
if (isEdge(x, y))
{
find_next(x, y);
dfs(nx, ny);
}
else
{
//온 적이 없으면
if (!check[x][y])
{
//만약 U, D, L, R 중 갈 수 있는 곳이 있는지 확인 후 변경
if (isConnection(x, y, direction[i]))
{
//노드 위치 체크
check[x][y] = true;
if (find_next(x, y)) dfs(nx, ny);
else return;
}
}
}
}
}
int main(void) {
int test_case;
cin >> test_case;
for (int i = 0; i < test_case; i++) {
cin >> N;
//초기화
init();
//입력
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
cin >> map[j][k];
if (map[j][k]) core.push_back(make_pair(j, k));
}
}
for (int i = 0; i < core.size(); i++) {
dfs(core[i].first, core[i].second);
init();
}
}
}
-
전체 길이는 나중에 check에 1인 녀석들을 다 합치면 된다 :)
-
문제1. map을 boolean으로 하다보니 map이 갱신될 때마다 코어와 길을 구분할 수가 없었다. - 타입변경
-
문제2. 연결된 코어의 개수를 우선순위로 하는 코드가 빠짐
-
문제3. 방향별로 돌 때 map을 갱신하는 것을 잊음..
예제실수 ㅎㅎ..
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>
#define INF 987654321
using namespace std;
int n, nx, ny, pnum, res;
int map[13][13], dist[13];
char direction[4] = { 'U', 'D', 'L', 'R' };
bool isLine(int x, int y, int dir) {
//0동,1남,2서,3북
if (dir == 0) {
for (int i = y + 1; i < n; i++) {
if (map[x][i] != 0)return false;
}
}
else if (dir == 1) {
for (int i = x + 1; i < n; i++) {
if (map[i][y] != 0)return false;
}
}
else if (dir == 2) {
for (int i = 0; i < y; i++) {
if (map[x][i] != 0)return false;
}
}
else {
for (int i = 0; i < x; i++) {
if (map[i][y] != 0) return false;
}
}
return true;
}
int draw_line(int x, int y, int dir, int flag) {
int ans = 0;
if (dir == 0) {
for (int i = y + 1; i < n; i++) {
map[x][i] = (flag == 0) ? 2 : 0;
ans++;
}
}
else if (dir == 1) {
for (int i = x + 1; i < n; i++) {
map[i][y] = (flag == 0) ? 2 : 0;
ans++;
}
}
else if (dir == 2) {
for (int i = 0; i < y; i++) {
map[x][i] = (flag == 0) ? 2 : 0;
ans++;
}
}
else {
for (int i = 0; i < x; i++) {
map[i][y] = (flag == 0) ? 2 : 0;
ans++;
}
}
return ans;
}
void dfs(vector<pair<int,int>> &v, int idx, int num, int line) {
if (idx == v.size()) {
// 최대프로세서 갯수가 갱신되는 경우
if (pnum < num) {
res = line;
pnum = num;
}
// 최대프로세서 갯수가 같은 경우
else if (pnum == num) {
if (res > line) res = line;
}
}
else {
// 4방향에대해 라인놓기 시도 + 라인 놓지않고 다음 프로세서로 넘어가는 경우
// 총 5가지에 대해 탐색
for (int i = 0; i < 4; i++) {
if (isLine(v[idx].first, v[idx].second, i)) {
dfs(v, idx + 1, num + 1, line + draw_line(v[idx].first, v[idx].second, i, 0));
draw_line(v[idx].first, v[idx].second, i, 1);
}
}
dfs(v, idx + 1, num, line);
}
}
int main(void) {
int test_case;
cin >> test_case;
for (int i = 1; i <= test_case; i++) {
cin >> n;
vector<pair<int,int>> core;
//입력
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
cin >> map[j][k];
//여기 인풋 받는데가 문제였다.
//if (i == 0 || j == 0 || i == n - 1 || j == n - 1) continue;
if (j == 0 || k == 0 || j == n - 1 || k == n - 1) continue;
if (map[j][k]) core.push_back(make_pair(j, k));
}
}
res = INF;
pnum = 0;
dfs(core,0, 0, 0 );
cout << "#" << i << " " << res <<endl;
}
}
댓글남기기