코테 노트/백준

백준 15686 치킨 배달 C++

화요밍 2021. 8. 4. 21:07
728x90
반응형

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

 

15686번: 치킨 배달

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸

www.acmicpc.net

 

최종 코드

 

GitHub - hwayeon351/BEAKJOON-Algorithms: 백준 알고리즘 소스 코드 모음

백준 알고리즘 소스 코드 모음. Contribute to hwayeon351/BEAKJOON-Algorithms development by creating an account on GitHub.

github.com

//
//  main.cpp
//  BJ15686
//
//  Created by Hwayeon on 2021/08/04.
//

#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;

int N, M;
int map[51][51] = {0,};
vector<pair<int, int>> house;
vector<pair<int, int>> chicken_shop;
vector<pair<int, int>> survive_chicken_shop;

int answer = 20001;

int cal_chicken_distance(){
    int chicken_distance = 0;
    for(int h=0; h<house.size(); h++){
        int hx = house[h].first;
        int hy = house[h].second;
        int min_dis = 100;
        for(int c=0; c<survive_chicken_shop.size(); c++){
            int cx = survive_chicken_shop[c].first;
            int cy = survive_chicken_shop[c].second;
            int n_dis = abs(cx-hx) + abs(cy-hy);
            if(min_dis > n_dis){
                min_dis = n_dis;
            }
        }
        chicken_distance += min_dis;
    }
    return chicken_distance;
}

void choose_chicken_shop(int cnt, int idx){
    //폐업시키지 않을 치킨집을 M개 고른 경우,
    if(cnt == M){
        int chicken_distance = cal_chicken_distance();
        if(answer > chicken_distance) answer = chicken_distance;
        return;
    }
    if(M-cnt > chicken_shop.size()-(idx+1)) return;
    for(int i=idx+1; i<chicken_shop.size(); i++){
        survive_chicken_shop.push_back(chicken_shop[i]);
        choose_chicken_shop(cnt+1, i);
        survive_chicken_shop.pop_back();
    }
}

int main(int argc, const char * argv[]) {
    cin >> N >> M;
    for(int i=1; i<=N; i++){
        for(int j=1; j<=N; j++){
            cin >> map[i][j];
            //집인 경우,
            if(map[i][j] == 1){
                house.push_back({j, i});
            }
            //치킨 집인 경우,
            else if(map[i][j] == 2){
                chicken_shop.push_back({j, i});
            }
        }
    }
    choose_chicken_shop(0, -1);
    cout << answer << endl;
    return 0;
}

풀이 과정

풀이 시간 35분

//
//  main.cpp
//  BJ15686
//
//  Created by Hwayeon on 2021/08/04.
//

#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;

int N, M;
int map[51][51] = {0,};

//집의 위치를 담는 벡터
vector<pair<int, int>> house;
//치킨집의 위치를 담는 벡터
vector<pair<int, int>> chicken_shop;
//폐업하지 않고 남을 치킨집의 위치를 담는 벡터
vector<pair<int, int>> survive_chicken_shop;

//도시의 치킨거리의 최솟값을 최대의 경우로 초기화
//대략 어림잡아 치킨집이 (50,50)에 위치하고 집이 (1,1)에 100개 있는 경우로 적용
int answer = 10000;

//도시의 치킨 거리를 계산하는 함수
int cal_chicken_distance(){
    int chicken_distance = 0;
    for(int h=0; h<house.size(); h++){
        int hx = house[h].first;
        int hy = house[h].second;
        int min_dis = 100;
        for(int c=0; c<survive_chicken_shop.size(); c++){
            int cx = survive_chicken_shop[c].first;
            int cy = survive_chicken_shop[c].second;
            int n_dis = abs(cx-hx) + abs(cy-hy);
            if(min_dis > n_dis){
                min_dis = n_dis;
            }
        }
        chicken_distance += min_dis;
    }
    return chicken_distance;
}

void choose_chicken_shop(int cnt, int idx){
    //폐업시키지 않을 치킨집을 M개 고른 경우, 도시의 치킨거리를 구한다
    if(cnt == M){
        int chicken_distance = cal_chicken_distance();
        if(answer > chicken_distance) answer = chicken_distance;
        return;
    }
    
    //치킨집을 M개 고를 수 없는 경우, return
    if(M-cnt > chicken_shop.size()-(idx+1)) return;
    
    //M개의 치킨집 조합을 구한다
    for(int i=idx+1; i<chicken_shop.size(); i++){
        survive_chicken_shop.push_back(chicken_shop[i]);
        choose_chicken_shop(cnt+1, i);
        survive_chicken_shop.pop_back();
    }
}

int main(int argc, const char * argv[]) {
    cin >> N >> M;
    for(int i=1; i<=N; i++){
        for(int j=1; j<=N; j++){
            cin >> map[i][j];
            //집인 경우, house 벡터에 위치 추가
            if(map[i][j] == 1){
                house.push_back({j, i});
            }
            //치킨 집인 경우, chicken_shop 벡터에 위치 추가
            else if(map[i][j] == 2){
                chicken_shop.push_back({j, i});
            }
        }
    }
    //폐업하지 않고 남을 M개의 치킨집을 결정 -> DFS 활용
    choose_chicken_shop(0, -1);
    cout << answer << endl;
    return 0;
}
//시간복잡도 = O(n^3), 공간복잡도 = O(N^2)

최대 연산 횟수를 구해보면, N이 최대 50, M이 최대 6(M은 최대 13이지만 치킨집의 조합공식에서 가장 큰 연산횟수가 나오기 위해서 6으로 설정한다.), 집의 개수 최대 2N = 100, 치킨집의 개수 X는 최대 13인 경우를 생각해볼 수 있다.

즉, 치킨집의 조합 xCm = 13C6 = 1716, 도시의 치킨 거리 계산 2N*M = 2*50*13 = 1300이 소요된다.

최대 연산 횟수 = xCm * 2N * M = 2230800이므로 1초 내에 문제를 풀 수 있다.


이전 풀이

//
//  main.cpp
//  BJ15686
//
//  Created by Hwayeon on 2021/04/14.
//

#include <iostream>
#include <vector>
using namespace std;

int city[50][50] = {0, };
int N, M;
struct location{
    int x;
    int y;
};
location loc;
vector<location> house, chicken;
int min_chicken = 987654321;
bool visit[13] = {false, };

void get_chicken_distance(int index, int cnt){
    if(cnt == M){
        int total_chicken_distance = 0;
        for(int h=0; h<house.size(); h++){
            int min_chicken_distance = 987654321;
            for(int c=0; c<chicken.size(); c++){
                if(visit[c]){
                    int chicken_distance = abs(house[h].x - chicken[c].x) + abs(house[h].y - chicken[c].y);
                    if(chicken_distance < min_chicken_distance) min_chicken_distance = chicken_distance;
                }
            }
            total_chicken_distance +=  min_chicken_distance;

        }
        if(total_chicken_distance < min_chicken) min_chicken = total_chicken_distance;
        return;
    }
    if(index >= chicken.size()) return;
    visit[index] = true;
    get_chicken_distance(index+1, cnt+1);
    visit[index] = false;
    get_chicken_distance(index+1, cnt);
}

int main(int argc, const char * argv[]) {
    cin >> N >> M;
    for(int i=0; i<N; i++){
        for(int j=0; j<N; j++){
            cin >> city[i][j];
            if(city[i][j] == 1){
                loc.x = j;
                loc.y = i;
                house.push_back(loc);
            }
            else if(city[i][j] == 2){
                loc.x = j;
                loc.y = i;
                chicken.push_back(loc);
            }
        }
    }
    get_chicken_distance(0, 0);
    cout << min_chicken << endl;
    
    return 0;
}
728x90
반응형

'코테 노트 > 백준' 카테고리의 다른 글

백준 1890 점프 Python3  (0) 2021.08.05
백준 9095 1, 2, 3 더하기 Python3  (0) 2021.08.04
백준 1463 1로 만들기 Python3  (0) 2021.08.04
백준 15683 감시 C++  (0) 2021.08.03
백준 14500 테트로미노 C++  (0) 2021.07.22