남은 도시를 모두 방문할 필요 없이, 가장 멀리 있는 도시 하나만 방문했다가 시작적으로 돌아가도 된다.
남은 도시들을 방문하는 방법이 꼭 일렬로 연결된 형태가 아니어도 된다.
단순한 휴리스틱 함수 구현
코드 11.2 단순한 휴리스틱을 이용한 가지치기의 구현
최적화
소형(n=12)
중형(n=16)
대형(n=20)
초대형(n=24)
동적계획법
0.03 sec
0.58 sec
26.45 sec
768.21 sec
완전탐색
89.74 sec
시간초과
시간초과
시간초과
최적해보다 나빠지면 그만두기
2.58 sec
981.53 sec
시간초과
시간초과
단순한 휴리스틱
0.85 sec
84.18 sec
시간초과
시간초과
가까운 도시부터 방문하기
코드 11.3 가까운 정점부터 방문하는 최적화의 구현
최적화
소형(n=12)
중형(n=16)
대형(n=20)
초대형(n=24)
동적계획법
0.03 sec
0.58 sec
26.45 sec
768.21 sec
완전탐색
89.74 sec
시간초과
시간초과
시간초과
최적해보다 나빠지면 그만두기
2.58 sec
981.53 sec
시간초과
시간초과
단순한 휴리스틱
0.85 sec
84.18 sec
시간초과
시간초과
가까운 도시부터 방문하기
0.52 sec
31.03 sec
시간초과
시간초과
지나온 경로를 이용한 가지치기
코드 11.4 지나온 경로를 이용하는 두 가지 가지치기 전략의 구현
최적화
소형(n=12)
중형(n=16)
대형(n=20)
초대형(n=24)
동적계획법
0.03 sec
0.58 sec
26.45 sec
768.21 sec
완전탐색
89.74 sec
시간초과
시간초과
시간초과
최적해보다 나빠지면 그만두기
2.58 sec
981.53 sec
시간초과
시간초과
단순한 휴리스틱
0.85 sec
84.18 sec
시간초과
시간초과
가까운 도시부터 방문하기
0.52 sec
31.03 sec
시간초과
시간초과
부분 경로 뒤집는 가지치기
0.07 sec
1.13 sec
33.29 sec
1160.81 sec
MST 휴리스틱을 이용한 가지치기의 구현
코드 11.5 MST 휴리스틱의 구현
최적화
소형(n=12)
중형(n=16)
대형(n=20)
초대형(n=24)
동적계획법
0.03 sec
0.58 sec
26.45 sec
768.21 sec
완전탐색
89.74 sec
시간초과
시간초과
시간초과
최적해보다 나빠지면 그만두기
2.58 sec
981.53 sec
시간초과
시간초과
단순한 휴리스틱
0.85 sec
84.18 sec
시간초과
시간초과
가까운 도시부터 방문하기
0.52 sec
31.03 sec
시간초과
시간초과
부분 경로 뒤집는 가지치기
0.07 sec
1.13 sec
33.29 sec
1160.81 sec
휴리스틱을 MST로 교체
0.06 sec
0.37 sec
14.77 sec
836.43 sec
마지막 단계 메모이제이션하기
코드 11.6 부분적으로 메모이제이션을 사용하는 최적화의 구현
// 남은 도시의 수가 CACHED_DEPTH 이하면 동적 계획법으로 바꾼다.constint CACHED_DEPTH = 5;
// dp(here, visited)=cache[here][남은 도시의 수][visited]
map<int,double> cache[MAX][CACHED_DEPTH+1]
/// here : 현재 위치// visited : 각 도시의 방문 여부 // 일 때, 나머지 도시를 모두 방문하고 시작점으로 돌아가는 최단 경로의 길이를 반환한다.double dp(int here, int visited){
// 기저사례 : 더 방문할 도시가 없으면 시작점으로 돌아간다.if(visited == (1<<n)-1) return dist[here][0];
// 메모이제이션int remaining = n - __builtin_popcount(visited);
double& ret = cache[here][remaining][visited];
if(ret > 0) return ret;
ret = INF;
// 다음 도시를 하나씩 시도한다.for(int next = 0; next < n; ++next){
if(visited & (1<<next)) continue;
ret = min(ret, dp(next, visited + (1<<next)) + dist[here][next]);
}
return ret;
}
void search(vector<int>& path, int visited, double currentLength) {
// 생략// 기저 사례 : 남은 도시 수가 CACHED_DEPTH 이하면 동적 계획법으로 바꾼다.if(path.size() + CACHED_DEPTH >= n){
best = min(best, currentLength + dp(path.back(), visited));
return;
}
// 생략
}
double solve(){
// 생략// cache 초기화for(int i = 0; i < MAX; ++i)
for(int j = 0; j <= CACHED_DEPTH; ++j)
cache[i][j].clear();
// 생략
}