πŸ•οΈ ICPC Sinchon/Shortest Path

[BOJ G3][C++] λ°±μ€€ 1865번: μ›œν™€

선달 2022. 11. 3. 17:31
λ°˜μ‘ν˜•

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

 

1865번: μ›œν™€

첫 번째 μ€„μ—λŠ” ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€μ˜ 개수 TC(1 ≤ TC ≤ 5)κ°€ 주어진닀. 그리고 두 번째 쀄뢀터 TC개의 ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€κ°€ μ°¨λ‘€λ‘œ μ£Όμ–΄μ§€λŠ”λ° 각 ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€μ˜ 첫 번째 μ€„μ—λŠ” μ§€μ μ˜ 수 N(1 ≤ N ≤ 500),

www.acmicpc.net

 

문제

λ•ŒλŠ” 2020λ…„, λ°±μ€€μ΄λŠ” μ›”λ“œλ‚˜λΌμ˜ ν•œ ꡭ민이닀. μ›”λ“œλ‚˜λΌμ—λŠ” N개의 지점이 있고 N개의 지점 μ‚¬μ΄μ—λŠ” M개의 λ„λ‘œμ™€ W개의 μ›œν™€μ΄ μžˆλ‹€. (단 λ„λ‘œλŠ” λ°©ν–₯이 μ—†μœΌλ©° μ›œν™€μ€ λ°©ν–₯이 μžˆλ‹€.) μ›œν™€μ€ μ‹œμž‘ μœ„μΉ˜μ—μ„œ 도착 μœ„μΉ˜λ‘œ κ°€λŠ” ν•˜λ‚˜μ˜ 경둜인데, νŠΉμ΄ν•˜κ²Œλ„ 도착을 ν•˜κ²Œ 되면 μ‹œμž‘μ„ ν•˜μ˜€μ„ λ•Œλ³΄λ‹€ μ‹œκ°„μ΄ λ’€λ‘œ κ°€κ²Œ λœλ‹€. μ›œν™€ λ‚΄μ—μ„œλŠ” μ‹œκ³„κ°€ 거꾸둜 κ°„λ‹€κ³  μƒκ°ν•˜μ—¬λ„ μ’‹λ‹€.

μ‹œκ°„ 여행을 맀우 μ’‹μ•„ν•˜λŠ” λ°±μ€€μ΄λŠ” ν•œ 가지 κΆκΈˆμ¦μ— λΉ μ‘Œλ‹€. ν•œ μ§€μ μ—μ„œ μΆœλ°œμ„ ν•˜μ—¬μ„œ μ‹œκ°„μ—¬ν–‰μ„ ν•˜κΈ° μ‹œμž‘ν•˜μ—¬ λ‹€μ‹œ μΆœλ°œμ„ ν•˜μ˜€λ˜ μœ„μΉ˜λ‘œ λŒμ•„μ™”μ„ λ•Œ, μΆœλ°œμ„ ν•˜μ˜€μ„ λ•Œλ³΄λ‹€ μ‹œκ°„μ΄ λ˜λŒμ•„κ°€ μžˆλŠ” κ²½μš°κ°€ μžˆλŠ”μ§€ μ—†λŠ”μ§€ κΆκΈˆν•΄μ‘Œλ‹€. μ—¬λŸ¬λΆ„μ€ 백쀀이λ₯Ό 도와 이런 일이 κ°€λŠ₯ν•œμ§€ λΆˆκ°€λŠ₯ν•œμ§€ κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ—¬λΌ.

μž…λ ₯

첫 번째 μ€„μ—λŠ” ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€μ˜ 개수 TC(1 ≤ TC ≤ 5)κ°€ 주어진닀. 그리고 두 번째 쀄뢀터 TC개의 ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€κ°€ μ°¨λ‘€λ‘œ μ£Όμ–΄μ§€λŠ”λ° 각 ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€μ˜ 첫 번째 μ€„μ—λŠ” μ§€μ μ˜ 수 N(1 ≤ N ≤ 500), λ„λ‘œμ˜ 개수 M(1 ≤ M ≤ 2500), μ›œν™€μ˜ 개수 W(1 ≤ W ≤ 200)이 주어진닀. 그리고 두 번째 쀄뢀터 M+1번째 쀄에 λ„λ‘œμ˜ 정보가 μ£Όμ–΄μ§€λŠ”λ° 각 λ„λ‘œμ˜ μ •λ³΄λŠ” S, E, T μ„Έ μ •μˆ˜λ‘œ 주어진닀. S와 EλŠ” μ—°κ²°λœ μ§€μ μ˜ 번호, TλŠ” 이 λ„λ‘œλ₯Ό 톡해 μ΄λ™ν•˜λŠ”λ° κ±Έλ¦¬λŠ” μ‹œκ°„μ„ μ˜λ―Έν•œλ‹€. 그리고 M+2번째 쀄뢀터 M+W+1번째 μ€„κΉŒμ§€ μ›œν™€μ˜ 정보가 S, E, T μ„Έ μ •μˆ˜λ‘œ μ£Όμ–΄μ§€λŠ”λ° SλŠ” μ‹œμž‘ 지점, EλŠ” 도착 지점, TλŠ” μ€„μ–΄λ“œλŠ” μ‹œκ°„μ„ μ˜λ―Έν•œλ‹€. TλŠ” 10,000보닀 μž‘κ±°λ‚˜ 같은 μžμ—°μˆ˜ λ˜λŠ” 0이닀.

두 지점을 μ—°κ²°ν•˜λŠ” λ„λ‘œκ°€ ν•œ κ°œλ³΄λ‹€ λ§Žμ„ μˆ˜λ„ μžˆλ‹€. μ§€μ μ˜ λ²ˆν˜ΈλŠ” 1λΆ€ν„° NκΉŒμ§€ μžμ—°μˆ˜λ‘œ 쀑볡 없이 맀겨져 μžˆλ‹€.

좜λ ₯

TC개의 쀄에 κ±Έμ³μ„œ λ§Œμ•½μ— μ‹œκ°„μ΄ μ€„μ–΄λ“€λ©΄μ„œ 좜발 μœ„μΉ˜λ‘œ λŒμ•„μ˜€λŠ” 것이 κ°€λŠ₯ν•˜λ©΄ YES, λΆˆκ°€λŠ₯ν•˜λ©΄ NOλ₯Ό 좜λ ₯ν•œλ‹€.

 

풀이

μš°μ„ .. μž…λ ₯이 μƒλ‹Ήνžˆ λ³΅μž‘ν•˜κ²Œ λ‚˜μ˜€λ―€λ‘œ 예제λ₯Ό 직접 λ¨Έλ¦¬μ†μœΌλ‘œ κ΅¬ν˜„ν•΄λ³΄λ©° μž…λ ₯ ν˜•νƒœλ₯Ό 잘 νŒŒμ•…ν•˜μž

 

λ„λ‘œ,,, μ›œν™€ κ½€λ‚˜ λ³΅μž‘ν•΄λ³΄μ΄μ§€λ§Œ κ²°λ‘ μ μœΌλ‘œλŠ”
κ°€μ€‘μΉ˜λ₯Ό ν•©ν–ˆμ„λ•Œ μŒμˆ˜κ°€ λ‚˜μ˜€λŠ” "μŒμ˜μ‚¬μ΄ν΄" 이 μžˆλŠ”μ§€λ§Œ ν™•μΈν•˜λ©΄ λœλ‹€

 

음의 κ°€μ€‘μΉ˜λ₯Ό μ§€λ‹Œ 간선이 μžˆμ„ λ•Œ μ΅œλ‹¨κ²½λ‘œλ₯Ό κ΅¬ν•˜κΈ° μœ„ν•΄ 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•΄λ³΄λ©΄

[🌲 Altu-Bitu/1101 μ΅œλ‹¨κ²½λ‘œ] - λ°±μ€€ 11657번: νƒ€μž„λ¨Έμ‹ 

μ΅œλ‹¨κ²½λ‘œλ₯Ό κ΅¬ν•˜λŠ” κ³Όμ •μ—μ„œ 음의 사이클을 λ°œκ²¬ν–ˆμ„ λ•Œ ν•¨μˆ˜λ₯Ό μ€‘λ‹¨ν•΄μ€˜μ•Όν•œλ‹€.
이 뢀뢄을 μ΄μš©ν•˜μ—¬ λ³Έ λ¬Έμ œμ—μ„œλŠ” μŒμ˜μ‚¬μ΄ν΄μ˜ 쑴재 μ—¬λΆ€λ§Œ μ•Œμ•„λ‚΄λ©΄ λœλ‹€.

 

κ½€ 였랜 고민을 톡해 ν’€μ—ˆλŠ”λ°,,

κ·Έ 고민의 흔적은 μ½”λ“œ μ•„λž˜ μ‹œν–‰μ°©μ˜€μ—.. γ… γ… 

// Authored by : seondal
// Co-authored by : -

// #include <bits/stdc++.h>
#include <iostream>
#include <vector>
#include <tuple>

using namespace std;

typedef tuple<int, int, int> tp;

const int INF = 6e7; // κ±Έλ¦¬λŠ” μ‹œκ°„μ˜ μ΅œλŒ“κ°’ : κ°„μ„ κ°―μˆ˜(2500+2500+500)*μ‹œκ°„(10000) = 52e6

bool isThereNegativeCycle(int n, int path, vector<tp>&edges) {
        vector<int> dist(n+1, INF);
        
        for(int i=1; i<=n; i++) {
            for(int j=0; j<path; j++) {
                int s, d, w;
                tie(s,d,w) = edges[j];
                
                int next_weight = dist[s] + w;
                if(next_weight < dist[d]) {
                    dist[d] = next_weight;
                    
                    if(i==n)
                        return true;
                }
            }
        }
    
    return false;
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    
    int tc, n,m,w, s,e,t;
    cin >> tc;
    while(tc--) {
        // μž…λ ₯
        cin >> n >> m >> w;
        vector<tp> edges; // κ°„μ„  정보 μ €μž₯
        for(int i=0; i<m; i++) { // λ„λ‘œμ •λ³΄ μž…λ ₯λ°›κΈ° (μ–‘λ°©ν–₯)
            cin >> s >> e >> t;
            edges.push_back({s, e, t});
            edges.push_back({e, s, t});
        }
        for(int i=0; i<w; i++) { // μ›œν™€μ •λ³΄ μž…λ ₯λ°›κΈ° (단방ν–₯)
            cin >> s >> e >> t;
            edges.push_back({s, e, t*-1});
        }
        
        // 좜λ ₯
        if(isThereNegativeCycle(n, 2*m+w, edges))
            cout << "YES\n";
        else
            cout << "NO\n";
    }
    
    return 0;
}

/*
 */

 

μ‹œν–‰μ°©μ˜€ 1

μ˜ˆμ œλŠ” 잘 λ˜λŠ”λ° 5% μ •λ„μ—μ„œ ν‹€λ ΈμŠ΅λ‹ˆλ‹€ κ°€ λœ¨λŠ”κ²½μš°,
μ‹œμž‘μ μ΄ λ‹¨μ ˆλ˜μ–΄μžˆμ–΄μ„œ μŒμ˜μ‚¬μ΄ν΄μ΄ λ‚˜μ˜€μ§€ μ•Šμ€ 경우λ₯Ό κ³ λ €ν•˜μž

 

μ‹œν–‰μ°©μ˜€ 2

μœ„ μ‹œν–‰μ°©μ˜€1을 κ²ͺκ³ ,

μ²˜μŒμ—λŠ” λͺ¨λ“  점을 λ²¨λ§Œν¬λ“œ(λ‹€μ΅μŠ€νŠΈλΌ)의 μ‹œμž‘μ μœΌλ‘œ 돌렀보며 음의 사이클을 μ°Ύμ•˜λŠ”λ°
94% μ •λ„μ—μ„œ μ‹œκ°„μ΄ˆκ³Ό κ°€ λ–΄λ‹€.

// for문으둜 돌렀주기
bool isThereNegativeCycle(int start, int n, int path, vector<tp>&edges) {
    
    while(start <= n) {
        vector<int> dist(n+1, INF);
        dist[start] = 0;
        
        for(int i=1; i<=n; i++) {
            for(int j=0; j<path; j++) {
                int s, d, w;
                tie(s,d,w) = edges[j];
                
                if(dist[s] == INF)
                    continue;
                
                int next_weight = dist[s] + w;
                if(next_weight < dist[d]) {
                    dist[d] = next_weight;
                    
                    if(i==n)
                        return true;
                }
            }
        }
        start++;
    }
    
    return false;
}
// μž¬κ·€ν•¨μˆ˜λ‘œ 돌렀보기
bool isThereNegativeCycle(int start, int n, int path, vector<tp>&edges) {
    
    if(start>n) // λͺ¨λ“  정점을 μ‹œμž‘μ μœΌλ‘œ ν•΄λ΄€μŒμ—λ„ μŒμ‚¬μ΄ν΄μ΄ μ—†λ‹€λ©΄
        return false;
    
    vector<int> dist(n+1, INF);
    dist[start] = 0;
    
    for(int i=1; i<=n; i++) {
        for(int j=0; j<path; j++) {
            int s, d, w;
            tie(s,d,w) = edges[j];
            
            if(dist[s] == INF)
                continue;
            
            int next_weight = dist[s] + w;
            if(next_weight < dist[d]) {
                dist[d] = next_weight;
                
                if(i==n)
                    return true;
            }
        }
    }

    return isThereNegativeCycle(start+1, n, path, edges);
}

 

μ•„λ¬΄λž˜λ„ λ°˜λ³΅λ¬Έμ„ 3μ€‘μœΌλ‘œ λŒλ¦¬λŠ”κ±΄ λ¬΄λ¦¬μ˜€λ‹€.

μ‹œκ°„μ„ μ–΄λ–»κ²Œ μ€„μΌμ§€λ§Œ 고민을 ν–ˆλŠ”λ°,,

 

μ•Œκ³ λ³΄λ‹ˆ μ‹œμž‘μ μ€ μ€‘μš”ν•˜μ§€ μ•Šμ•˜λ‹€ (!)

 

λ³Έ μ•Œκ³ λ¦¬μ¦˜μ„ 돌렀보며 μŒμ˜μ‚¬μ΄ν΄μ΄ μžˆλŠ”μ§€λ§Œ ν™•μΈν•˜λ©΄ 되기 λ•Œλ¬Έμ—
dist[start]=0 으둜 μ΄ˆκΈ°ν™”ν•˜λŠ” 과정도,

dist[d]==INF λ₯Ό νŒλ‹¨ν•˜λŠ” 과정도,

μ „ν˜€ ν•„μš”ν•˜μ§€ μ•Šμ•˜λ‹€.

 

μ°Έκ³ 

https://4z7l.github.io/2021/03/04/algorithms-boj-1865.html

 

[C++ μ•Œκ³ λ¦¬μ¦˜] λ°±μ€€ 1865번 : μ›œν™€ - HERSTORY

λ²¨λ§Œν¬λ“œ <!-- ### --> 풀이과정 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ„ μ΄μš©ν•΄ ν•΄κ²°ν•˜μ˜€λ‹€. μ‹œκ°„μ΄ μ€„μ–΄λ“€λ©΄μ„œ 좜발 μœ„μΉ˜λ‘œ λŒμ•„μ˜€λŠ” 것 을 보고 λ²¨λ§Œν¬λ“œλ₯Ό λ– μ˜¬λ¦¬κΈ° λ„λ‘œλŠ” 무방ν–₯μ΄λ―€λ‘œ μ–‘λ°©ν–₯ κ°„μ„  2개λ₯Ό μΆ”κ°€

4z7l.github.io

 

λ°˜μ‘ν˜•