/**
* money:8000, coins:[5000,1000,500,100,50,10] 일때
* 거스름돈을 최소한으로 사용하는 방법
*/
public int greedy(int money, int[] coins) {
int cnt=0;
for(int coin:coins) {
if(money >= coin) {
cnt+=money/coin;
money%=coin;
}
}
return cnt;
}
void dfs(int depth,int now,int[] arr) {
// check finished
if(isFin) return;
// end
if(depth==n) {
// check answer
if(check(arr)) isFin=true;
return;
}
// next
for(int next=0;next<n;next++) {
// DFS 는 아래와 같은 문법이 반복되어 사용됨!
if(visited[next]) continue;
arr[depth]=now;
visited[depth]=true;
dfs(depth+1,next,arr);
// 방문 후 반드시 흔적을 지워줘야함.
arr[depth]=-1;
visited[depth]=false;
}
}
Queue<int[]> que=new LinkedList<>(); // (y,x,depth)
que.add(new int[]{0,0,1});
int minDepth=0;
boolean[][] visited=new boolean[n][m];
int[] dy={1,0,-1,0},dx={0,1,0,-1};
while(!que.isEmpty()) {
int[] now=que.poll();
int y=now[0],x=now[1],depth=now[2];
// visited
if(visited[y][x]) continue;
visited[y][x]=true;
// check end
if(y==n-1 && x==m-1) {
minDepth=depth;
break;
}
// next
for(int d=0;d<4;d++) {
int my=y+dy[d],mx=x+dx[d];
if(my<0 || my>=n || mx<0 || mx>=m) continue;
if(!graph[my][mx] || visited[my][mx]) continue;
que.add(new int[]{my,mx,depth+1});
}
}
단순히 라이브러리를 쓰면 되는 문제도 있고
각 정렬을 구현해볼줄 알아야함.
int[] arr={5,4,1,2,3};
for(int i=0;i<arr.length;i++) {
int minIdx=i;
// compare
for(int j=i+1;j<arr.length;j++) {
if(arr[minIdx]>arr[j]) minIdx=j;
}
// swap (i, minIdx)
int tmp=arr[minIdx];
arr[minIdx]=arr[i];
arr[i]=tmp;
}
int[] arr={5,4,1,2,3};
for(int i=1;i<arr.length;i++) {
for(int j=i;j>=0;j--) {
// 작다면 스왑
if(arr[j]<arr[j-1]) {
int tmp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=tmp;
}
else break;
}
}
void quick_sort(int s,int e,int[] nums) {
if(s>=e) return;
// partition
int pivot=s,l=s+1,r=e;
while(l<=r) {
// swap 할 l,r 을 찾는 과정
while(e>=l && nums[pivot]>=nums[l]) l++;
while(r>=s+1 && nums[r]>=nums[pivot]) r--;
// swap
// 마지막이라면 (pivot,r) 아니라면 (l,r) swap
swap(l>r?pivot:l,r,nums);
}
// divide
// 마지막에 r과 pivot 스왑해서 r이 pivot
quick_sort(s,r-1,nums);
quick_sort(r+1,e,nums);
}
private void swap(int a,int b,int[] nums) {
int tmp=nums[b];
nums[b]=nums[a];
nums[a]=tmp;
}
#임의의 배열
array=[4,5,0,1,9,7,6]
count=[0]*(max(array)+1)
for i in range(len(array)):
count[array[i]]+=1
# 정렬된 정보 확인
for i in range(len(count)):
for j in range(count[i]):
print(i,end=' ')
int[] arr={5,4,1,2,3};
int max=0;
for(int a:arr) max=Math.max(max,a);
boolean[] isIn=new boolean[max+1];
for(int a:arr) isIn[a]=true;
for(int i=0;i<isIn.length;i++) if(isIn[i]) System.out.println(i);
void merge_sort(int l,int r,int[] nums,int[] sorted) {
// 크기>=2
if(l>=r) return;
int mid=(l+r)/2;
merge_sort(l,mid,nums,sorted);
merge_sort(mid+1,r,nums,sorted);
// merge
// l mid,mid+1 r
int lIdx=l,rIdx=mid+1;
for(int i=l;i<=r;i++) {
// 한쪽이 비었을때
if(rIdx>r) sorted[i]=nums[lIdx++];
else if(lIdx>mid) sorted[i]=nums[rIdx++];
// 비교
else sorted[i]=(nums[lIdx]<nums[rIdx])?nums[lIdx++]:nums[rIdx++];
}
// copy
for(int i=l;i<=r;i++) nums[i]=sorted[i];
}
int binary_search(int target) {
int s=0;e=n-1;
while(s<=e) {
int mid=(s+e)/2;
int midValue=arr[mid];
if(midValue==target) return mid;
else if(midValue<target) s=mid+1;
else e=mid-1;
}
// not found
return -1;
}
다이나믹 프로그램으로 풀 수 있는 문제는
재귀와 반복문으로 풀수있는데 반복문이 힙영역을 쓰지않아 메모리 초과를 막을수있다.
재귀로 풀면 탑다운 방식이고 반복문을 사용한다면 바텀업 방식이라고 볼수있다.
그래서 먼저 바텀업으로 시도해보자.
예제 코드
int dp(int n,int k) {
if(k==0 || k==n) return 1;
if(dt[n][k]!=0) return dt[n][k];
else if(dt[n][n-k]!=0) return dt[n][n-k];
dt[n][n-k]=dt[n][k]=(dp(n-1,k)+dp(n-1,k-1))%MOD_NUM;
return dt[n][k];
}
한점에서 다른 점들까지의 최소 거리
시작 노드에서 다른 노드까지의 거리를 찾고
최단 거리 노드를 방문하며 시작 노드로부터의 경로를 최소화.
모든 노드를 방문할때까지 반복.
노드중 가장 짧은 거리를 찾을때 모든 노드를 탐색하는것이 아닌 우선순위 큐를 사용하면 logV번으로 줄일 수 있다. 총 시간복잡도는 ElogV다
// dijkstra
PriorityQueue<Node> pq=new PriorityQueue<>(((o1, o2) -> o1.v-o2.v));
int start=1;
pq.add(new Node(start,0));
int[] dist=new int[vertex_size+1];
for(int i=1;i<=vertex_size;i++) dist[i]=INF;
dist[start]=0;
while(!pq.isEmpty()) {
Node now=pq.poll();
// end
if(now.v==vertex_size) break;
// visited
if(dist[now.v]<now.w) continue;
// next
for(Node next:graph[now.v]) if(dist[next.v]>dist[now.v]+next.w) {
dist[next.v]=dist[now.v]+next.w;
pq.add(new Node(next.v,dist[next.v]));
}
}
for(int k=0;k<n;k++) {
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
graph[i][j]=Math.min(graph[i][j],graph[i][k]+graph[k][j]);
}
}
}
union-find(크루스칼 알고리즘), 위상 정렬
int parent=new int[10001];
int find(int x){
if(parent[x]!=x){
parent[x]=find(parent[x]);
}
return parent[x];
}
void unionParent(int a,int b){
a=find(a);
b=find(b);
// set parent
parent[a]=b;
}
트리가 깊어지면 rank 개념을 넣어서 더 높이가 작은게 아래로 가게 넣어줘야함
int parent=new int[10001];
int ranks=new int[10001];
int find(int x){
if(parent[x]!=x){
parent[x]=find(parent[x]);
}
return parent[x];
}
void unionParent(int a,int b){
a=find(a);
b=find(b);
if(a==b){
return;
}
// rank를 비교하고 작은쪽을 큰쪽에 넣기
if (ranks[a]<ranks[b]){
parent[a]=b;
}
else{
parent[b]=a;
}
if (ranks[a]==ranks[b]){
ranks[a]++;
}
}
신장트리 : 모든 노드가 연결되면서 사이클을 이루지 않는 그래프
최소신장트리 : 신장트리중에 간선의 합이 최소인 신장트리
크루스칼 알고리즘 : 간선을 오름차순으로 정렬하고 간선의 부모가 다르면 union. 간선의 합이 최소인 최소신장트리 생성됨.
from collections
import deque
v,e=map(int,input().split())
indegree=[0]*(v+1)
graph=[[] for _ in range(v+1)]
for _ in range(e):
a,b=map(int,input().split())
graph[a].append(b)
indegree[b]+=1
def topology_sort():
q=deque()
result=[]
for i in range(1,v+1):
if indegree[i]==0:
q.append(i)
while q:
now=q.popleft()
result.append(now)
for node in graph[now]:
indegree[node]-=1
if indegree[node]==0:
q.append(node)
return result
res=topology_sort()
for r in res:
print(r,end=' ')
import java.util.*;
public class Main {
static int n, m;
static int[] in = new int[32001];
static boolean[] visited = new boolean[32001];
public static void main(String[] args) throws IOException {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
n = Integer.paseInt(br.readLine());
m = Integer.paseInt(br.readLine());
List<List<Integer>> list = new ArrayList<>();
for (int i = 0; i <= n; i++) {
list.add(new ArrayList<>());
}
for (int i = 0; i < m; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
in[b]++;
list.get(a).add(b);
}
Queue<Integer> que = new LinkedList<>();
// 진입차수 0인 노드부터 시작
for (int i = 1; i <= n; i++) {
if (in[i] == 0) que.offer(i);
}
while (!que.isEmpty()) {
int now = que.poll();
visited[now] = true;
System.out.print(now + " ");
for (int i = 0; i < list.get(now).size(); i++) {
int out = list.get(now).get(i);
in[out]--;
if (in[out] == 0) que.offer(out);
}
}
// 남은 노드 출력 (진입차수가 남는 노드는 없다고 가정)
for (int i = 1; i <= n; i++) {
if (!visited[i]) System.out.print(i + " ");
}
}
}
코딩테스트 공부순서
백준 상단 문제메뉴 - 알고리즘 분류