본문 바로가기
알고리즘

[알고리즘] 치킨 배달

by keel_im 2021. 3. 7.
반응형

포인트

1. 조합을 이용을 하여 m개 까지 치킨집을 구할 수 있는가?

조합을 구하는 건 보통 3가지가 있는 것 같다. 

- 순열을 활용하여 조합을 구성하는 방법

- 확인 배열을 만들고 조합을 구성하는 방버

- 선택, 비선택 원리를 이용하여 조합을 구하는 방법 (제일 직관적이라고 생각합니다.)

2. 재귀를 잘 할 수 있는가? 

<2021.03.07> 

- 파이썬으로도 도전을 해보자

🧶문서는 항상 수정 될 수 있습니다. 비판은 환영합니다. 

재귀 조합을 이용하여 푸는 방법

// 본인이 조합을 구할 때 주로 쓰는 방법
#include<iostream>
#include<vector>
#include <algorithm>

using namespace std;

int n, m;
int map[51][51];

vector<pair<int, int>> house, chicken, sel;
vector<int> dists;


int distance() {
    int a = 0;
    for (auto ele1 : house) {
        int dist = 987654321;
        for (auto ele2 : sel) {
            int Dist = abs(ele2.first - ele1.first) + abs(ele2.second - ele1.second);
            dist = min(dist, Dist);
        }
        a += dist;
    }
    return a;
}

void go(int index, int cnt) {
    if (cnt == m) {
        dists.push_back(distance());
        return;
    }

    if (index >= chicken.size()) return;

    sel.push_back(chicken[index]);
    go(index + 1, cnt + 1);
    sel.pop_back();

    go(index + 1, cnt);
}


int main(void) {

    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
            if (map[i][j] == 1) house.push_back(make_pair(i, j));
            if (map[i][j] == 2) chicken.push_back(make_pair(i, j));
        }
    }

    go(0, 0);
    cout << *min_element(dists.begin(), dists.end()) << '\n';
    return 0;
}

 

순열을 이용하여 푸는 방법

#include <iostream>
#include <tuple>
#include <vector>
#include <algorithm>

using namespace std;
int n, m;
vector<pair<int, int>> house;
vector<pair<int, int>> chicken;

int main() {
    cin >> n >> m;
    vector<vector<int>> map(n, vector<int>(n));

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
            if (map[i][j] == 1) house.push_back({i, j});
            if (map[i][j] == 2) chicken.push_back({i, j});
        }
    }
    vector<int> d(chicken.size());
    for (int i = 0; i < m; i++) {
        d[i] = 1;
    }
    sort(d.begin(), d.end()); // 순열은 항상 정렬
    int answer = 987654321;
    do {
        int a = 0;
        for (auto ele1 : house) {
            vector<int> dists;
            for (int i = 0; i < chicken.size(); i++) {
                if (d[i] == 0) continue;
                auto ele2 = chicken[i];
                dists.push_back(abs(ele1.first - ele2.first) + abs(ele1.second - ele2.second));
            }
            a += *min_element(dists.begin(), dists.end());
        }

        answer = min(answer, a);
    } while (next_permutation(d.begin(), d.end()));
    cout << answer << '\n';
    return 0;
}

 

재귀 순열을 이용하여 구하는 방법

#include <iostream>
#include <vector>
#include <tuple>

using namespace std;

int n, m, answer;
int map[50][50];
bool sel[13];

vector<pair<int, int>> house, chicken, vc;

int calcDistance() {
    int sum = 0;
    for (int i = 0; i < house.size(); i++) {
        int x, y;
        tie(x, y) = house[i];
        int d = 99999999;

        for (int j = 0; j < vc.size(); j++) {
            int xx, yy;
            tie(xx, yy) = vc[j];
            int dist = abs(xx - x) + abs(yy - y);

            d = min(d, dist);
        }
        sum += d;
    }
    return sum;
}

void go(int idx, int count) { //재귀 함수
    if (count == m) {
        answer = min(answer, calcDistance());
        return;
    }

    for (int i = idx; i < chicken.size(); i++) {
        if (sel[i] == true) continue;
        sel[i] = true;
        vc.push_back(chicken[i]);
        go(i, count + 1);
        sel[i] = false;
        vc.pop_back();
    }
}

int main() {
    answer = 99999999;
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
            if (map[i][j] == 1) house.push_back(make_pair(i, j));
            if (map[i][j] == 2) chicken.push_back(make_pair(i, j));
        }
    }
    go(0, 0);

    cout << answer << endl;
}

2021 03 07

n, m = map(int, input().split())

data = [list(map(int, input().split())) for _ in range(n)]

chicken = []
house = []
for i in range(n):
    for j in range(n):
        if data[i][j] == 2:
            chicken.append([i, j])
        if data[i][j] == 1:
            house.append([i, j])

distance = []
sel = []


def go(index: int, cnt: int):
    if cnt == m:
        a = 0
        for ele1, ele2 in house:
            dist = 987654321
            for ele3, ele4 in sel:
                dist = min(dist, abs(ele3 - ele1) + abs(ele4 - ele2))
            a += dist
        distance.append(a)
        return

    if index >= len(chicken):
        return

    sel.append(chicken[index])
    go(index + 1, cnt + 1)
    sel.pop()

    go(index + 1, cnt)


go(0, 0)
print(min(distance))
반응형

'알고리즘' 카테고리의 다른 글

[알고리즘] Top K Frequent Elements  (0) 2021.03.08
[알고리즘] 로봇 청소기  (0) 2021.03.07
[알고리즘] Permutations  (0) 2021.03.04
[알고리즘] missing Number  (0) 2021.03.04
[알고리즘] Distribute Candies  (0) 2021.03.02

댓글