문자열 - 아호 코라식(Aho-Corasick)
아호 코라식(Aho-Corasick)에 대해 알아보자.
[18253 최단경로와 쿼리] https://www.acmicpc.net/problem/18253 .
쿼리를 한번에 계산하는 테크닉을 배워보자.
처음으로 풀게된 다이아 문제이고 참 좋은 문제라는 생각이 들어서 포스팅한다.
문제상황은 간단하다 일단 Naive하게 짠다고 하면 각 쿼리마다 다익스트라를 하는 방법이고 이는 당연히 시간초과다.
그래도 다익스트라를 이용하여 최단거리를 구할 수 있다는 것을 생각할 수 있다.
처음에는 각 쿼리를 빠르게 계산하는 방법을 떠올렸다.
하지만 그러려면 쿼리가 최대 10만이므로 각연산을 로그시간만에 끝내야한다.
쿼리 구간이 크게 주어진다면 다익스트라를 하면서 쿼리 각 연산을 로그시간안에 끝내기가 까다로웠다.
쿼리마다 연산을 하는 것이 아니라 한번에 모든 쿼리를 연산해야했다.
이를 위한 가장 중요한 아이디어는 N이 작다는 것이다.(최대 5)
N이 작고 어느 지점에서 다른 지점으로 가기 위해서는 그 사이에 있는 한 줄(세로줄)을 무조건 건너야만 한다.
그래서 가운데 세로줄에 대해 다익스트라를 하면 n번의 다익스트라로 구간 최소를 구할 수 있다.
한번의 분할 정복을 하면서 모든 쿼리를 연산해두는 것이다.
class Query{
public:
int y1, x1, y2, x2, idx;
Query(){}
Query(int a, int b, int c, int d, int e){
y1 = a; x1 = b; y2 = c; x2 = d;
idx = e;
}
};
위와 같이 쿼리 클래스를 만들고 배열에 저장해뒀다.
이 문제는 위와 같은 아이디어로 구현을 한다고 하더라도 최적화에 꽤 많은 신경을 써야한다.
그 중에서 나의 문제는
나머지 주의 할 점은 코드에 주석으로 처리했다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define fast_io cin.tie(NULL); cout.tie(NULL); ios_base::sync_with_stdio(false);
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
class Query{
public:
int y1, x1, y2, x2, idx;
Query(){}
Query(int a, int b, int c, int d, int e){
y1 = a; x1 = b; y2 = c; x2 = d;
idx = e;
}
};
const int dy[] = {-1, 1, 0, 0};
const int dx[] = {0, 0, 1, -1};
const ll INF = 500000000000001;
int n, m; //STL이 느려서 그런가...
Query query[100001]; //push_back이 느려서 그런가??
ll grid[6][100001];
ll res[100001];
ll dist[6][100001];
void dijkstra(int sy, int sx, int range1, int range2){
for(int i=1;i<=n;i++){
for(int j=range1;j<=range2;j++) dist[i][j] = INF;
}
priority_queue<pair<ll, pii>> pq;
dist[sy][sx] = grid[sy][sx];
pq.push({-dist[sy][sx], {sy, sx}});
while (!pq.empty()) {
int hy = pq.top().second.first, hx = pq.top().second.second;
ll nowcost = -pq.top().first;
pq.pop();
if(dist[hy][hx]<nowcost) continue;
for(int i=0;i<4;i++){
int ny = hy+dy[i], nx = hx+dx[i];
if(ny<1||ny>n||nx<range1||nx>range2) continue;
ll nextcost = nowcost+grid[ny][nx];
if(dist[ny][nx]>nextcost){
dist[ny][nx]= nextcost;
pq.push({-nextcost, {ny, nx}});
}
}
}
}
void solveDNC(int L, int R, Query qu[], int qusize){
if(!qusize||L>R) return;
int mid = (L+R)>>1;
for(int i=1;i<=n;i++){ // (i, mid)에서 다익스트라를 해서 쿼리 중 이곳을 지나는 최솟값을 갱신한다.(n번 다익스트라함)
dijkstra(i, mid, L, R);
for(int j=0;j<qusize;j++){
res[qu[j].idx] = min(res[qu[j].idx], dist[qu[j].y1][qu[j].x1]+dist[qu[j].y2][qu[j].x2]-grid[i][mid]);
}
}
Query left[qusize];
Query right[qusize];
int lsize= 0, rsize =0;
for(int i=0;i<qusize;i++){ //mid를 안지나도 되는 경우를 넣는다
if(qu[i].x1<mid&&qu[i].x2<mid) left[lsize++] = qu[i]; // 쿼리범위가 mid보다 작을 때
else if(qu[i].x2>mid&&qu[i].x1>mid) right[rsize++] = qu[i]; //쿼리범위가 mid보다 클 때
}
solveDNC(L, mid-1, left, lsize);
solveDNC(mid+1, R, right, rsize);
}
int main(){
fast_io;
cin >> n >> m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin >> grid[i][j];
}
}
int q; cin >> q;
for(int i=0;i<q;i++){
int r1, c1, r2, c2;
cin >> r1 >> c1 >> r2 >> c2;
if(c1>c2){
swap(r1, r2);
swap(c1, c2);
}
Query q(r1, c1, r2, c2, i);
query[i] = q;
}
for(int i=0;i<q;i++) res[i] = INF;
solveDNC(1, m, query, q); //한번에 모든 쿼리를 계산
for(int i=0;i<q;i++){
cout << res[i] << '\n';
}
}
아호 코라식(Aho-Corasick)에 대해 알아보자.
docker를 이해해보자
2060 염소줄서기 풀이 및 코드
분할정복을 이용한 다이나믹 프로그래밍 최적화
코드포스 다시 열심히! 블로그도 열심히!
rust 공부시작!
코드포스 블루 달성 후기
여름캠프 및 SUAPC 후기
2023-05-25-Edu Codeforce round 149 (Div.2)
2023-05-13-Edu Codeforce round 148 (Div.2)
HLD(Heavy Light Decomposition)
행렬 거듭 제곱
2023-05-02-It takes two
Codeforce round 868 (Div.2)
2월 11일 문제풀이
Codeforces#846, TypeDB Foreces 2023, Codeforces#848 업솔빙
ps5 게임 : 용과같이 제로 리뷰
백준 23877번 Convoluted Intervals 문제풀이
codeforce round #828(div 3), EDU #137(div 2) 업솔빙
codeforce round #823(div 2), #824(div 2) 업솔빙
AtCoder Beginner Contest 270 업솔빙
ps5 게임 : 용과같이 극 1 리뷰
백준 18719번 Binomal 문제풀이
백준 14288번 회사문화4 문제풀이
백준 3308번 Matching 문제풀이
백준 18186번 라면사기(large) 문제풀이
백준 4196번 도미노 문제풀이
백준 3176번 도로 네트워크 문제풀이
백준 16367번 TV Show Game 문제풀이
ps5 게임 : 페르소나 5 더 로열 리뷰
codeforce round #811(div 3), #812(div 2), CodeTon round 2 업솔빙
백준 21162번 뒤집기 K 문제풀이
codeforce round #808(div 2), #803(div 2, virtual) 업솔빙
codeforce round #807(div 2) 업솔빙
백준 10167번 금광 문제풀이
codeforce round #805(div 3), #806(div 4) 업솔빙
백준 18253번 최단경로와 쿼리 문제풀이
에듀 라운드 131 업솔빙
백준 1949번 우수 마을 문제풀이
백준 3665번 최종 순위 문제풀이
Trie 자료구조 이해하기
merge sort를 이용하여 inversion 개수세기
3솔의 벽이 너무 높다..
lazy propagation없이 구간 갱신하기
코드포스 폭망기념 upsolving
백준 11505 구간 곱 구하기 문제풀이
백준 1305 광고 문제풀이
백준 4386 별자리 만들기 문제풀이
백준 4803 트리
백준 2206 벽 부수고 이동하기 문제풀이
백준 2166 다각형의 면적 문제풀이
백준 12015 가장 긴 증가하는 부분 수열2 문제풀이
백준 10986 나머지합 문제풀이
스택 구현하기 ========== 자료구조의 기본이라고 하면 스택 과 큐가 있다 백준 10828번에서 마주친 스택
매우매우 많은 정렬이 있지만 그중 가장 안 어려운 3가지를 공부해보았다.
Leave a comment