티스토리 뷰

DS\Algo

BOJ 1420 학교 가지마!

MathTrauma 2022. 8. 30. 03:08

 

문제 링크 : https://www.acmicpc.net/problem/1420

 

1420번: 학교 가지마!

첫째 줄에 도시의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 100) 둘째 줄부터 N개의 줄에 도시의 모양이 주어진다. 비어있으면 점('.'), 벽은 '#', 도현이의 위치는 K, 학교의 위치는 H이다.

www.acmicpc.net

 

출발 정점(도현이의 위치)이나 도착 정점(학교)의 주변을 벽으로 막으면...

맵 모양에 관계없이 답은 4 이하임을 알 수 있다.  

따라서 등교를 막을 수 없는 경우를 체크할 때, 유량이 4를 초과하는 것을 이용할 수 있다.

 

 

하여간 4 이하인 값 찾기 위해 '유량 네트워크'를 써야 하다니?

다른 방법이 없을까 생각해 보아야겠다.

 

문제로 돌아가서 어떻게 모델링을 할 것인가를 생각해 보자.

 

최소의 개수로 벽을 세우면 학교를 못가게 만드는 정점들을 알고 있다고 가정하자.

정점들을 한 번만 이용할 수 있도록 모델링하면 가능한 경로 수가 차단에 필요한 정점의 개수와 일치하게 된다.

경로의 수는 정점을 분할하고 분할된 정점 사이의 간선의 용량을 1로 하면 최대 유량이 될 것이고...

 

위 내용을 다르게 표현하면 간선 용량이 1 일 때, Minimum Cut 을 찾는 문제가 된다는 얘기.

사실 분할된 정점 사이의 용량을 1로 두면 나머지 간선은 아무렇게나 두어도 된다.

그래서 도현이와 학교가 인접하는 경우를 따로 확인하기 귀찮아서

유량이 4를 초과하도록 다른 간선들은 큰 값의 capacity 를 적용했다.

 

#include<bits/stdc++.h>

using namespace std;

const int Inf=1e9;

char str[101][101];

struct MF{
    struct edge{ 
        int to, cap, rev;
    };
    
    int sz, Src, Ter;
    vector<vector<edge>> adj;
    vector<int> level, work;
    
    MF(int sz, int S, int T) : sz{sz}, Src{S}, Ter{T} {
        adj=vector<vector<edge>>(sz);
    };
    
    bool bfs(){
        level=vector<int>(sz, -1);
        level[Src]=0;
        queue<int> q;
        q.push(Src);
        
        while(!q.empty() && level[Ter]==-1){
            int cur=q.front();
            q.pop();
            for(int i=0;i<adj[cur].size();i++){
                edge te=adj[cur][i];
                int nxt=te.to;
                if(level[nxt]==-1 && te.cap>0){
                    level[nxt]=level[cur]+1;
                    if(nxt==Ter) break;
                    q.push(nxt);
                }
            }
        }
        return level[Ter]!=-1;
    }
    
    int dfs(int cur, int flow){
        if(cur==Ter) return flow;
        for(int &i=work[cur];i<adj[cur].size();i++){
            edge te=adj[cur][i];
            int nxt=te.to;
            if(level[nxt]==level[cur]+1 && te.cap>0){
                int f=dfs(nxt, min(flow, te.cap));
                if(!f) continue;
                
                adj[cur][i].cap-=f;
                adj[nxt][te.rev].cap+=f;
                
                return f;
            }
        }
        return 0;
    }
    
    int solve(){
        int tFlow=0;
        while(bfs()){
            work=vector<int>(sz,0);
            while(1){
                int flow=dfs(Src, Inf);
                if(!flow) break;
                tFlow+=flow;
            }
        }
        return tFlow;
    }
    
    void link(int u, int v, int cap){
        adj[u].push_back({v, cap, (int)adj[v].size()});
        adj[v].push_back({u, 0, (int)adj[u].size()-1});
    }
};

int main(){
    int n,m; scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) scanf("%s", str[i]);
    
    MF mf(2*n*m, 0,1);
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(str[i][j]=='#') continue;
            if(str[i][j]=='K')  mf.Src=2*(i*m+j)+1;
            if(str[i][j]=='H')  mf.Ter=2*(i*m+j);
            
            mf.link(2*(i*m+j), 2*(i*m+j)+1, 1);
            
            if(i<n-1 && str[i+1][j]!='#'){
                mf.link(2*(i*m+j)+1, 2*((i+1)*m+j), Inf);
                mf.link(2*((i+1)*m+j)+1, 2*(i*m+j), Inf);
            }
                       
            if(j<m-1 && str[i][j+1]!='#'){
                mf.link(2*(i*m+j)+1, 2*(i*m+j+1), Inf);
                mf.link(2*(i*m+j+1)+1, 2*(i*m+j), Inf);
            }
        }
    }
    
    int ans=mf.solve();
    if(ans>4) printf("-1\n");
    else printf("%d\n", ans);
}

 

굳이 한마디 첨언해 두자면

인접 리스트를 쓰면서 각 간선에 대해 역간선을 만들면

인접 행렬을 쓰는 경우와 달리 그래프가 simple 일 것을 강요하지 않는다.

따라서 가급적 인접 행렬를 쓰지 않는 쪽이 좋을 것이다.

반응형

'DS\Algo' 카테고리의 다른 글

BOJ 13911 집구하기  (0) 2022.09.01
BOJ 11409 열혈강호 6 (MCMF 알고리즘 타당성)  (0) 2022.08.31
BOJ 11405 책 구매하기  (0) 2022.08.29
BOJ 2316 도시 왕복하기 2  (0) 2022.08.26
BOJ 11932 트리와 K번째 수  (0) 2022.08.26
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함