반응형

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

 

1987번: 알파벳

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다. 말은 상하좌우로 인접한 네 칸 중의 한 칸으

www.acmicpc.net

1.문제설명

2 4
CAAB
ADCB

다음과 같이 알파벳으로 이루어진 보드가 주어질 때

각 알파벳은 한 번씩만 방문할 수 있다.

좌측 상단(C)에서 시작해서 상하좌우로 이동하여

이동할 수 있는 최대 칸 수를 구해야한다.

 

 

백준 1987번 알파벳
백준 1987번 알파벳

D로 이동하면 D에서 상하좌우를 보면

위는 이미 방문해서 갈 수 없고 좌우는 이미 지난 알파벳이어서 방문할 수 없어서

D에서 깊이탐색이 끝나게 되고,

이동 거리는 3이다.

 

 

2.접근방법[알고리즘]

이 문제는 말이 최대한 몇칸을 움직일 수 있는지 구해야하는 문제다.

보통 DFS나 BFS로 최단거리를 많이 구하는데 이 문제는 다르게

이동할 수 있는 최대 거리를 구해야한다.

 

그리고 각 알파벳 마다 한번 씩만 방문할 수 있다.

방문한 알파벳을 저장해주면서 DFS 탐색을 돌아

최대 이동 거리를 갱신해주어야 한다.

 

 

2-1. 방문한 노드 좌표는 따로 저장을 안해주어도 되나?

방문한 알파벳을 저장해주면 알파벳 정보에

방문한 노드 정보까지 자연스럽게 포함된다

예를 들어 전에 방문한 노드가 C라면 C를 저장해주면

노드 번호를 따로 저장해주지 않아도 다음 노드가 C이면 탐색을 하지 않는다.

그러므로 방문한 알파벳만 저장하고 체크하면 된다.

 

 

2-2. DFS 코드

DFS(x좌표, y좌표, 이동거리) 이렇게 매개변수를 두고

dist가 최대일 때마다 갱신해주면서 깊이탐색 했다.

 

bool 배열 ch_alpha에 해당 알파벳이 이미 방문된 알파벳인지 체크해준다.

백트래킹을 돌면서 최대 이동거리를 갱신한다.

int r, c, ans;
char arr[21][21];
bool ch_alpha[26];

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

void DFS(int x, int y, int dist) {
	
	ans = max(ans, dist);

	for (int i = 0; i < 4; i++) {
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
		
		int next_alpha = arr[nx][ny] - 'A';
		if (ch_alpha[next_alpha] == 0) {
			ch_alpha[next_alpha] = 1;
			DFS(nx, ny, dist + 1);
			ch_alpha[next_alpha] = 0;
		}
	}
}

 

 

 

 

3.문제풀이코드 C++

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

int r, c, ans;
char arr[21][21];
bool ch_alpha[26];

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

void DFS(int x, int y, int dist) {
	
	ans = max(ans, dist);

	for (int i = 0; i < 4; i++) {
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
		
		int next_alpha = arr[nx][ny] - 'A';
		if (ch_alpha[next_alpha] == 0) {
			ch_alpha[next_alpha] = 1;
			DFS(nx, ny, dist + 1);
			ch_alpha[next_alpha] = 0;
		}
	}
}

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

	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			cin >> arr[i][j];
		}
	}

	ch_alpha[arr[0][0] - 'A'] = 1;
	DFS(0, 0, 1);

	cout << ans << '\n';

}

백준 1987번 시간 및 메모리

 

반응형
반응형

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

 

 

1759번: 암호 만들기

첫째 줄에 두 정수 L, C가 주어진다. (3 ≤ L ≤ C ≤ 15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.

www.acmicpc.net

1. 문제설명

순열이나 조합을 만드는 문제와 비슷하다. 차이점은 숫자 대신 문자를 출력한다는 점이다.

조건에서 구해야 하는 암호는 항상 사전순으로 이루어져있어야하고

최소 한 개의 모음(a, e, i, o, u)과 최소 두 개의 자음으로 구성되어 있어야한다.

 

 

입력

4 6
a t c i s w

출력

acis
acit
aciw
acst
acsw
actw
aist
aisw
aitw
astw
cist
cisw
citw
istw

 

 

2. 접근 방법[알고리즘]

먼저 증가하는 순열(조합)을 만들고 그 순열에 알파벳 순으로 덮어준다고 생각하면 쉽다.

다만 문제에서 사전순이라는 조건과 모음과 자음의 갯수 조건이 있으므로

우선 알파벳 순열을 만들어주고 그 알파벳 순열이 조건에 부합한다면 출력해주면 된다.

 

 

 

우선 증가하는 순열을 만들어보자. 

6개의 숫자에서 4개의 숫자를 뽑는 조합을 만든다고 생각해도 동일하다.

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

int L, C, path[20], ch[20] , t=1;
char a[20], ans[20];

void DFS(int cur) {
	if (t == L+1) {
		for (int i = 1; i <= L; i++) {
			cout << path[i] << ' ';
		}
		cout << '\n';

	}
	else {
		for (int i = cur; i <= C; i++) {
			if (ch[i] == 0) {
				ch[i] = 1;
				path[t++] = i;
				DFS(i);
				ch[i] = 0;
				t--;
			}
		}
	}
}

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


	DFS(1);
}

 

조합 출력

 

이제 각 숫자에 해당 알파벳을 적용하면 된다

알파벳은 문제 조건에 따라 사전순으로 정렬되어야한다.

a t c i s w
번호 1 2 3 4 5 6
알파벳 a c i s t w

 

1759 암호만들기

이제 알파벳 까지 적용해서 잘 만들었다.

하지만 cstw는 문제 조건에서 모음이 한개이상 있어야하므로 출력되면 안된다.

↓ 지금 단계 까지의 코드

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

int L, C, path[20], ch[20] , t=1;
char a[20], ans[20];

void DFS(int cur) {
	if (t == L+1) {
		int cnt1 = 0;
		//for (int i = 1; i <= L; i++) {
		//	ans[i] = a[path[i]];
		//	if (ans[i] == 'a' || ans[i] == 'e' ||
		//		ans[i] == 'i' || ans[i] == 'o' || ans[i] == 'u') {
		//		cnt1++;
		//	}
		//}

		//if (cnt1 >= 1 && L - cnt1 >= 2) {
		//	for (int i = 1; i <= L; i++) {
		//		cout << ans[i];
		//	}
		//	cout << '\n';

		//}

		for (int i = 1; i <= L; i++) {
			cout << a[path[i]] << ' ';
		}
		cout << '\n';

	}
	else {
		for (int i = cur; i <= C; i++) {
			if (ch[i] == 0) {
				ch[i] = 1;
				path[t++] = i;
				DFS(i);
				ch[i] = 0;
				t--;
			}
		}
	}
}

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

	for (int i = 1; i <=C; i++) {
		cin >> a[i];
	}
	sort(a+1 , a + 1 + C);

	DFS(1);
}

 

마지막으로 출력하기전에 모음과 자음 갯수를 카운트해

조건에 부합하면 출력하면된다.

cnt1 변수로 모음갯수만 세서 전체 알파벳 갯수인 L에서 cnt1을 빼주면 자음갯수를 구할 수 있다.

 

3.문제풀이코드 C++

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

int L, C, path[20], ch[20] , t=1;
char a[20], ans[20];

void DFS(int cur) {
	if (t == L+1) {
		int cnt1 = 0;
		for (int i = 1; i <= L; i++) {
			ans[i] = a[path[i]];
			if (ans[i] == 'a' || ans[i] == 'e' ||
				ans[i] == 'i' || ans[i] == 'o' || ans[i] == 'u') {
				cnt1++;
			}
		}

		if (cnt1 >= 1 && L - cnt1 >= 2) {
			for (int i = 1; i <= L; i++) {
				cout << ans[i];
			}
			cout << '\n';

		}
	}
	else {
		for (int i = cur; i <= C; i++) {
			if (ch[i] == 0) {
				ch[i] = 1;
				path[t++] = i;
				DFS(i);
				ch[i] = 0;
				t--;
			}
		}
	}
}

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

	for (int i = 1; i <=C; i++) {
		cin >> a[i];
	}
	sort(a+1 , a + 1 + C);

	DFS(1);
}

DFS, 백트래킹을 이용하여 조합을 만들어주고

 

문제 조건을 적용하면 해결되는 문제이다.

반응형
반응형

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

 

2583번: 영역 구하기

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오

www.acmicpc.net

 

 

 

1. 문제설명

 

2583번 문제
2583번 문제

모눈 종이에 직사각형이 그려져 있을 때

직사각형이 색칠되어 있지 않은 남은 부분들의 갯수와 부분들의 넓이를 구해서

오름차순으로 정렬해 출력하면 된다.

사각형의 갯수가 곧 넓이가 된다.

 

 

 

 

 

2. 접근방법[알고리즘]

색칠된 부분을 저장하기 위해 M*N 배열을 만들어야한다.

좌표를 설정하는 걸 조심해야한다.

 

2583번 좌표설정

N, M은 7,5지만 이건 꼭짓점이고 실제로

해당 칸 마다 좌표를 부여하면 (0,0) ~ (6,4)까지만 사용 한다.

 

 

입력

5 7 3
0 2 4 4
1 1 2 5
4 0 6 2

arr[i][j]의 값에 색칠되었다면 -1을 저장하고 색칠되지 않았다면 0을 저장해준다.

색칠해줄 때도 (0,2)에서 (4,4)까지 칠해주는게 아니라 (0,2)에서 (3,3)까지 칠해주어야한다.

이유는 위와 동일하게 (4,4)는 사각형의 해당 좌표가아니라 꼭짓점이기 때문이다.

 

	//직사각형 -1로 칠하기
	for (int i = 0; i < k; i++) {
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		for (int j = y1; j < y2; j++) { // y1 ~ <y2 까지 돌아야 한다
			for (int k = x1; k < x2; k++) { // x1 ~ <x2 까지 돌아야 한다
				arr[j][k] = -1;
			}
		}
	}

 

 

 

 

그리고 arr배열 값이 -1인 좌표는 BFS를 돌지 않고

arr배열이 0인 값만 탐색한다.

 

이제 arr배열을 돌면서 값이 0인 좌표를 발견하면

BFS를 실행하면서 arr 값에 사각형의 개수를 저장해준다.

 

2583번 문제

BFS 실행 코드

arr값이 0인 좌표를 발견할 때 arr 값을 1로 저장해준다. 

cnt 변수는 arr값이 0인 좌표를 발견했을 때 +1 해주어 전체 하얀 부분의 개수를 구할 수 있다.

this_area 변수는 BFS를 돌면서 0인좌표를 발견할 때마다 +1 해주어 해당 부분의 넓이를 저장해준다

그리고 Q가 empty가 되어 BFS가 끝나면 해당 하얀 부분을 다 탐색했다는 뜻이므로

this_area 변수의 값을 ans에 저장해준다.

 

이렇게 모든 좌표에대해 탐색하면 하얀 부분의 넓이를 모두 구할 수 있다.

	queue<pair<int, int> > Q;

	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (arr[i][j] == 0) {
				cnt++;
				arr[i][j] = 1;
				int this_area = 1;
				Q.push(make_pair(i, j));

				while (!Q.empty()) {
					int cur_x = Q.front().first;
					int cur_y = Q.front().second;
					Q.pop();

					for (int k = 0; k < 4; k++) {
						int nx = cur_x + dx[k];
						int ny = cur_y + dy[k];
						if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;
						if (arr[nx][ny] == 0) {
							arr[nx][ny] = ++this_area;
							Q.push({ nx,ny });
						}
					}
				}
				ans.push_back(this_area);
			}
		}
	}

 

 

 

 

3.문제풀이코드 C++

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

int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };
int n,m,k, cnt, arr[101][101];
vector<int> ans;

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

	//색칠영역 -1로 두고
	//-1이 아닌 곳 BFS 돌면서 넓이 구해주면 된다
	cin >> m >> n >> k;

	//직사각형 -1로 칠하기
	for (int i = 0; i < k; i++) {
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		for (int j = y1; j < y2; j++) {
			for (int k = x1; k < x2; k++) {
				arr[j][k] = -1;
			}
		}
	}

	//직사각형 확인
	//cout << "------------------------\n";
	//for (int i = 0; i < m; i++) {
	//	for (int j = 0; j < n; j++) {
	//		cout << arr[i][j] << ' ';
	//	}
	//	cout << '\n';
	//}
	//cout << "-------------------\n";

	queue<pair<int, int> > Q;

	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (arr[i][j] == 0) {
				cnt++;
				arr[i][j] = 1;
				int this_area = 1;
				Q.push(make_pair(i, j));

				while (!Q.empty()) {
					int cur_x = Q.front().first;
					int cur_y = Q.front().second;
					Q.pop();

					for (int k = 0; k < 4; k++) {
						int nx = cur_x + dx[k];
						int ny = cur_y + dy[k];
						if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;
						if (arr[nx][ny] == 0) {
							arr[nx][ny] = ++this_area;
							Q.push({ nx,ny });
						}
					}
				}
				ans.push_back(this_area);
			}
		}
	}


	//결과 확인
	//for (int i = 0; i < m; i++) {
	//	for (int j = 0; j < n; j++) {
	//		cout << arr[i][j] << ' ';
	//	}
	//	cout << '\n';
	//}
	//cout << "-------------------\n";


	//정답 출력
	cout << cnt << '\n';
	sort(ans.begin(), ans.end());
	for (int i = 0; i < ans.size(); i++) {
		cout << ans[i] << ' ';
	}

}

백준 2583 시간, 메모리

일반적인 BFS탐색 문제와 비슷하다.

 

다만 좌표설정하는 부분을 잘 유의해야할 필요가 있다.

 

 

반응형
반응형

Django runserver 이용하여 실행하기

//윈도우
python manage.py runserver
python manage.py runserver //8888(port)

//Mac
python3 manage.py runserver

 

myproject  > urls.py

"""myproject URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls'))
]

myapp >  urls.py 라우터

 

from django.urls import path
from myapp import views

urlpatterns = [
    path('', views.index),
    path('create/',views.create),
    path('read/<id>/',views.read), #read 함수의 파라미터에 id값 전해줌
    path('delete/', views.delete),
    path('update/<id>/',views.update),
]

 

myapp > views.py

from django.http import HttpResponse
from django.shortcuts import render,redirect
import random
from django.views.decorators.csrf import csrf_exempt

def HTMLTemplate(articleTag, id=None):
    global topics
    contextUI = ''
    if id!=None:
        contextUI = f'''
                <li>
                    <form action="/delete/" method="post">
                        <input type="hidden" name="id" value={id}>
                    <input type="submit" value="delete">
                    </form>
                </li>       
                <li><a href="/update/{id}">update</a></li> 
            '''
    ol = ''
    for topic in topics:
        ol += f'<li><a href="/read/{topic["id"]}">{topic["title"]}</a></li>'
    
    return f'''
    <html>
    <body>
        <h1><a href="/">Django</a></h1>
        <ol>
            {ol}
        </ol>
        {articleTag}
        <ul>
            <li><a href="/create/">create</a></li>
            {contextUI}
        </ul> 
    </body>
    </html>
    '''

nextId = 4
topics = [
    {'id':1, 'title':'routing', 'body':'Routing is ..'},
    {'id':2, 'title':'view', 'body':'View is ..'},
    {'id':3, 'title':'Model', 'body':'Model is ..'}
]
# Create your views here.
def index(request):
    article = '''
    <h2>Welcome</h2>
    Hello, Django
    '''
    return HttpResponse(HTMLTemplate(article))

 
def read(request,id):
    global topics
    article = ''
    for topic in topics:
        if topic['id'] == int(id):
            article = f'<h2>{topic["title"]}</h2>{topic["body"]}'

    return HttpResponse(HTMLTemplate(article, id))




@csrf_exempt
def create(request):
    global nextId
    print("request.method", request.method)
    if request.method == "GET":
        article ='''
            <form action="/create/" method="post">
                <p><input type="text" name="title" placeholder="title"></p>
                <p><textarea name="body" placeholder="body"></textarea></p>
                <p><input type="submit"></p>
            </form>
        '''
        return HttpResponse(HTMLTemplate(article))
    elif request.method == "POST":
        print(request.POST['title'])
        title = request.POST['title']
        body = request.POST['body']
        newTopic = {"id":nextId, "title":title, "body":body}
        topics.append(newTopic)
        url = '/read/'+str(nextId)
        nextId+=1
        return redirect(url)

@csrf_exempt
def delete(request):
    global topics
    if request.method == "POST":
        id = request.POST['id']
        newTopics = []

        for topic in topics:
            if topic['id'] != int(id):
                newTopics.append(topic)
        topics = newTopics
        return redirect('/')

@csrf_exempt
def update(request, id):
    global topics

    if request.method == 'GET':
        for topic in topics:
            if topic['id'] == int(id):
                selectedTopic = {
                    "title" : topic['title'],
                    "body" : topic['body'],
                }
        article =f'''
            <form action="/update/{id}/" method="post">
                <p><input type="text" name="title" value={selectedTopic["title"]}></p>
                <p><textarea name="body">{selectedTopic["body"]}</textarea></p>
                <p><input type="submit"></p>
            </form>
        '''
        return HttpResponse(HTMLTemplate(article, id))
    elif request.method == 'POST':
        title = request.POST['title']
        body = request.POST['body']
        for topic in topics:
            if topic['id'] == int(id):
                topic['title'] = title
                topic['body'] = body
        return redirect(f'/read/{id}')

 

생활코딩 강의

반응형
반응형

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

 

16964번: DFS 스페셜 저지

첫째 줄에 정점의 수 N(2 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N-1개의 줄에는 트리의 간선 정보가 주어진다. 마지막 줄에는 DFS 방문 순서가 주어진다. DFS 방문 순서는 항상 N개의 정수로 이루

www.acmicpc.net

 

1. 문제설명

입력으로 N개의 노드가 주어지고 노드간의 연결관계가 주어진다.

그리고 마지막 입력으로 DFS 방문 순서가 주어진다.

노드간의 연결관계를 바탕으로 깊이우선탐색을 할 때

주어진 방문 순서처럼 방문할 수 있는지 여부를 묻는 문제이다.

 

2.접근방법[알고리즘]

접근 방법은 문제 이름부터 DFS이기 때문에 쉽게 알 수 있다.

하지만 이 문제를 푸는 게 생각보다 많이 어려웠다.

그동안 DFS를 이용해 최단 거리나 백트래킹 위주 문제를 많이 풀다보니

처음 이 문제를 봤을 때

"주어진 정점과 간선을 통해 DFS로 탐색할 수 있는 모든 방문순서를 구해야하나?" 생각했다

 

그렇게 할 수도 있겠지만 그러면 시간초과할 것 같았다.

이 문제는 DFS의 방문 순서에대해 생각해보아야 해결 할 수 있다.

 

예제 입력을 갖고 생각해보자.

4
1 2
1 3
2 4
1 2 3 4

이렇게 주어졌을 때 그래프는 다음과 같다

 

백준 16964 그래프

 

DFS로 탐색 할 때 1번 노드에서 출발하면

2번, 3번 중 방문 순서를 택해야 한다.

 

2번을 먼저 방문하기로 택하면 

1 2 4 3 이렇게 탐색 하고

3번을 먼저 택하면 1 3 2 4 순서로 탐색하게 된다.

 

 

 

2번 노드와 3번 노드중 어떤 걸 먼저 탐색하게 해야 할까?

보통 일반적인 DFS나 BFS 문제에서는 어떤 노드를 먼저 탐색하게끔 문제를 만들지 않는다.

결과적으로 다 탐색한 뒤 어떤 결괏값을 갖는지를 많이 물어본다.

하지만 이 문제에서는 어떤 노드를 먼저 탐색할지 정해주는 과정이 필수적이다.

 

문제 입력 마지막 줄에 예상 DFS 탐색 순서를 준다.

만약 위처럼 1 2 3 4 이렇게 주어졌다면

우리는 깊이 우선 탐색을 할 때 2번 노드를 3번노드 보다 먼저 택해야한다.

 

만약 주어진 예상 DFS 탐색 순서가 1 3 2 4 라면

우리는 깊이 우선 탐색을 할 때 3번 노드를 2번노드 보다 먼저 택해야한다.

 

 

즉 마지막 예상 DFS 탐색 순서를 바탕으로해서

어떤 노드를 먼저 탐색해야할지 정해주고,

정해진 노드 탐색 순서를 바탕으로 DFS를 수행했을 때

예상 DFS 탐색 순서와 일치하는지 확인하는 문제이다.

 

노드간의 연결 관계를 인접리스트로 만들고,

인접리스트의 노드 순서를 정해진 노드 탐색 순서로 정렬한 뒤

깊이우선탐색을 실행해야 한다.

 

이해를 돕기 위해 다른 입력으로 생각해보자

(마지막 줄, DFS예상 탐색 순서만 다르다)

4
1 2
1 3
2 4
1 3 2 4

 

order

1 2 3 4
1 3 2 4

1,2,3,4 노드가 있을 때

항상 탐색 순서는

1번 노드가 첫번째

3번 노드가 두번째

2번 노드가 세번째

4번 노드가 네번째로 돌아야한다.

 

이를 위해 order 배열에 순서에 해당하는 노드를 저장해준다

order[2] = 3이면 우선 순위 두번째 노드가 3이라는 뜻이다.

 

그리고 이런 우선순위를 바탕으로 인접리스트의 노드들을 정렬해준다.

 

 

각 노드의 탐색 우선순위를 지정해주기 위한 코드다.

bool comp(int a, int b){
	return order[a] < order[b];
}
    
for(int i=1; i<=n; i++){
	int node;
	cin >> node; 
	given_path[i] = node;
	order[node] = i;
}
	
for(int i=1; i<=n; i++){
	sort(ad[i].begin(), ad[i].end(), comp);
}

 

sort를 시행하기 전

1번 노드는 2번 노드를 먼저 탐색한다.

출발 연결된 노드 (순서)
ad[1] 1번노드 2, 3
ad[2] 2번노드 1, 4
ad[3] 3번노드 1
ad[4] 4번노드 2

 

 

sort 한 후 3번이 2번보다 우선순위가 높기 때문에 2 앞으로 온다.

이제 DFS를 돌면 2보다 먼저 탐색된다.

출발 연결된 노드 (순서)
ad[1] 1번노드 3, 2
ad[2] 2번노드 1, 4
ad[3] 3번노드 1
ad[4] 4번노드 2

다시 설명하자면,

이렇게 해주는 이유는

문제 입력에서 1,3,2,4 순으로 탐색을 할 수 있는지 물어보았기 때문에 3은 무조건 2보다 먼저 탐색되야한다.

 

문제입력에 주어진 조건을 바탕으로 

각 노드마다 우선순위를 적용해준 뒤 탐색한 후 1,3,2,4 순으로 탐색이 되는지 확인하기 위함이다.

 

 

3. 문제풀이코드 C++

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

vector<int> ad[100001]; 
int order[100001], given_path[100001], DFS_path[100001], L=1;
bool ch[100001];

bool comp(int a, int b){
	return order[a] < order[b];
}

void DFS(int x){
	ch[x] = 1;
	DFS_path[L++] = x;
	
	for(int i=0; i<ad[x].size();i++){
		int nx = ad[x][i];
		if(ch[nx]==0) DFS(nx);
	}
}


int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n;
	cin >> n;
	
	for(int i=1; i<n; i++){
		int node1, node2;
		cin >> node1 >> node2;
		ad[node1].push_back(node2);
		ad[node2].push_back(node1);
	}
	
	// 각 노드마다 순서를 정해준다  
	for(int i=1; i<=n; i++){
		int node;
		cin >> node; 
		given_path[i] = node;
		order[node] = i;
	}
	
	for(int i=1; i<=n; i++){
		sort(ad[i].begin(), ad[i].end(), comp);
	}
	
	//1번부터 돌기 떄문  
	DFS(1);
	for(int i=1; i<=n; i++){
		if(given_path[i]!=DFS_path[i]){
			cout << 0;
			return 0;
		}
	}
	cout << 1;
	
	
}

백준 16964 메모리 , 시간

배열 대신 벡터로 동적으로 배열을 이용하면

메모리를 절약할 수 있겠지만 귀찮은 관계로 대부분 배열을 이용했다.

아마 인접리스트를 이용하지 않고 인접행렬[nxn]그래프를 이용하면 메모리 초과가 될 것이다.

 

인접리스트 알아보기

반응형
반응형

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

 

2252번: 줄 세우기

첫째 줄에 N(1 ≤ N ≤ 32,000), M(1 ≤ M ≤ 100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의

www.acmicpc.net

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


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

	int n,m;
	cin >> n >> m;
	
	vector<int> graph[32001];
	vector<int> degree(n+1, 0);
	
	for(int i=0; i<m;i++){
		int a,b;
		cin >> a >> b;
		
		graph[a].push_back(b);
		degree[b]++;
	}
	
	queue<int> Q;
	
	
	for(int i=1; i<=n; i++){
		if(degree[i]==0) Q.push(i);
	}
	
	while(!Q.empty()){
		int cur = Q.front();
		Q.pop();
		cout << cur <<' ';
		
		for(int i=0; i<graph[cur].size(); i++){
			int nx = graph[cur][i];
			degree[nx]--;
			if(degree[nx]==0) Q.push(nx);	
		}
	}
		
	
}

 

처음에 아무 생각없이 32000x32000 벡터를 만들었다가

메모리 초과로 틀렸다.

그래서 32000행 벡터를 만들고 노드를 인풋 받을 때마다 push_back 해주었다.

반응형
반응형

처음엔 그래프 거리를 구하는 걸 냅색 알고리즘을 어떻게 응용해야할지 모르겠어서

우선순위큐 BFS를 이용해 풀어봤다.

답은 맞았다.

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

int n, m;

int arr[101][101], ch[101];

struct Edge{
	int node, dist;
	Edge(int a, int b){
		node = a;
		dist = b;
	}
	bool operator<(const Edge &e) const{
		return dist > e.dist;
	}
	
};

priority_queue<Edge> Q;

int DIST(int s,int e){

	int res = INT_MAX;
	Q.push(Edge(s,0));
	
	while(!Q.empty()){
		int cur_node = Q.top().node;
		int cur_dist = Q.top().dist;
		Q.pop();
		ch[cur_node] = 1;
		if(cur_node == e){
			res = min(res, cur_dist);
		}
		
		for(int i=1; i<=n; i++){
			if(arr[cur_node][i]!=INT_MAX && ch[i]==0){
				Q.push(Edge(i, cur_dist+arr[cur_node][i]));
			}
		}
		
	}
	
	for(int i=1; i<=n; i++){
		ch[i] = 0;
	}
	
	
	return res;

}

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++){
			if(i==j) continue;
			arr[i][j] = INT_MAX;
		}
	}
	
	for(int i=1; i<=m; i++){
		int a,b,c;
		cin>> a >> b >> c;
		arr[a][b] = c;
	}

	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++){
			int ans = DIST(i,j);
			if(ans==INT_MAX) cout <<"M ";
			else cout << ans << " ";
		}
		cout <<'\n';
	}
	
}

 

플로이드워샬 알고리즘이란?

플로이드워샬 알고리즘모든 정점에서 모든 정점으로 가는 최단 거리를 구하는 알고리즘이다.

 

다익스트라 벨만포드 알고리즘과 플로이드워샬 알고리즘의 차이는?

다익스트라, 벨만포드 알고리즘한 정점에서 다른 정점으로 가는 최단 거리를 구한다는 점에서

플로이드워샬 알고리즘과 차이가 있다.

 

 

 

 

점화식

arr[i][j] 는 i노드에서 j노드로 가는 거리를 저장한다.

arr[i][j] = min(arr[i][j], arr[i][k]+arr[k][j]);

i노드에서 j노드로 가는 거리와

 

i노드에서 k노드를 거쳐 j 노드를 가는 거리를 비교해서 더 짧은 방법을 선택한다.

 

k에 대하여 존재하는 모든 노드를 한 번씩 다 적용시켜보면

 

모든 노드에서 모든 노드로 가는 최단 거리 테이블을 만들 수 있다.

 

 

플로이드 와샬

다음과 같은 그림이 있을 때

k노드를 선택하기 이전에

arr[i][j] = 20이었다.

 

i - > j 노드로 가는 것 보다

i -> k -> j 노드로 가는 게 더 짧다.

arr[i][j] = 18로 선택된다.

 

 

플로이드 와샬 그림 설명

추가적으로 t 노드가 있을 때

 

이제 i ->k ->j 보다

i-> k -> t -> j 노드로 가는 게 더 빠르다.

arr[i][j] = 18에서

arr[i][j] = arr[i][t] + arr[t][j] = 17로 갱신된다.

 

이런식으로 모든 노드에 대해서 갱신해주면

모든 노드에서 모든 노드로 가는 최단 거리를 구할 수 있다.

 

arr[i][j] = min(arr[i][j], arr[i][k]+arr[k][j]);

 

k번째 노드를 계속 선택해줘서 경유점으로 둘 때

최솟값을 계속 갱신해준다는 점에서 냅색알고리즘과 유사하다.

노드를 가방에 담을지 안담을지 선택한다고 보면 된다.

for(int k=1; k<=n; k++){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            if(arr[i][k]==INT_MAX || arr[k][j] == INT_MAX) continue;
            arr[i][j] = min(arr[i][j], arr[i][k]+arr[k][j]);
        }
    }
}

1부터 n까지 모든 노드 k에 대해서

k를 경유점으로 추가하는 것과 이전의 k를 경유점으로 추가하지 않는 것을 비교하면서

최솟값을 계속 저장해준다.

 

이러면 결과적으로 arr[i][j]에 i부터 j까지 가는 최단 거리가 저장된다.

(애초에 i에서 j로 갈 수 없는 점들은 INT_MAX로 초기화해두고 시작한다)

 

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

int n, m;

int arr[101][101];


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++){
			if(i==j) continue;
			arr[i][j] = INT_MAX;
		}
	}
	
	for(int i=1; i<=m; i++){
		int a,b,c;
		cin>> a >> b >> c;
		arr[a][b] = c;
	}

	for(int k=1; k<=n; k++){
		for(int i=1; i<=n; i++){
			for(int j=1; j<=n; j++){
				if(arr[i][k]==INT_MAX || arr[k][j] == INT_MAX) continue;
				arr[i][j] = min(arr[i][j], arr[i][k]+arr[k][j]);
			}
		}
	}
	
	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++){
			if (arr[i][j]==INT_MAX) cout << "M ";
			else cout << arr[i][j] << ' ';
		}
		cout << '\n';
	}
	
}

플로이드 와샬 알고리즘을 이용하면

맨위처럼 우선순위큐 BFS를 사용하지 않아도

간단하게 모든 노드에서 모든 노드로 가는 최단거리를 구할 수 있다.

반응형

'Algorithm > etc' 카테고리의 다른 글

cycle 찾기  (0) 2022.02.21
Segment Tree 구현 코드 C++  (0) 2022.02.11
냅색 알고리즘(한번 만 사용가능) 2차원, 1차원 배열  (0) 2022.01.26
냅색 문제  (0) 2022.01.26
LIS 최대 부분 증가수열 - DP  (0) 2022.01.25
반응형

리터럴 객체 선언

let func = (item1, item2) => item1 + item2;
console.log(func(1,2));

const emptyObject = {};

emptyObject.name = "LEee";
console.log(emptyObject.name);

const user = {
    age:20,
    name:"디디에 드록바",
    get_data: () => (1+2),
};
console.log(typeof user, user);
console.log(user.age);
console.log(user.name);
console.log(user.get_data());


const Lee = {
    age: 25,
    name : "Lee",
    details:{
        hobby: "coding",
        major: "software",
        get_detalis:function(item){
            return this.major;
        }
    },

    get get_age(){
        return this.age;
    },

    set set_age(value){
        this.age = value;
    }
}

console.log(typeof Lee, Lee);
console.log(Lee.age);
console.log(Lee.details.hobby);
console.log(Lee.details.get_detalis(4));

console.log(Lee.get_age);
Lee.set_age = 24;
console.log(Lee.get_age);

const a = new Object();

a.age = 10;
a.name = "Daa";
console.log(a.age, a.name);


function User(age, name){
    this.age = age;
    this.name = name;
}

const Kim = new User(3,"Kim");
console.log(typeof Kim);
console.log(Kim.age, Kim.name);

User.prototype.message = function(){
    return "hellow";
}

console.log(Kim.message());

 

클래스 객체 선언

class Animal{
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
}

class Dog extends Animal{
    constructor(name, age){
        super(name,age);
        
    }
    
    bark = function(){
        return "war war!";
    };
}


const shunider = new Dog("bbo", 12);
console.log(shunider.name);
console.log(shunider.age);
console.log(shunider.bark());
bbo
abc.js:23 12
abc.js:24 war war!

 

 

prototype과 hasOwnProperty

class Animal{
    constructor(name){
        this.name = name;
    }

    get_message(){
        return "Hello";
    }

}


Animal.prototype.age = 10;

const dog = new Animal("dog");
console.log(dog.hasOwnProperty('name')); //true
console.log(dog.hasOwnProperty('age')); //false

 

반응형

+ Recent posts