※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 8992번 문제인 집기 게임이다.
문제는 아래 링크를 확인하자.

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

 

8992번: 집기 게임

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 가로 선의 수 n과 세로 선의 수 m이 주어진다. (1 ≤ n,m ≤ 200) 다음 n개 줄에는 각 가로 선의 정보 x,y,x',y',w가 주어

www.acmicpc.net

가로선의 집합을 한 쪽, 세로선의 집합을 다른 쪽에 두고, source와 각 가로선을 capacity 1, 각 세로선과 sink를 capacity 1의 간선으로 잇고 서로 교차하는 가로선과 세로선의 쌍 사이에 capacity 1, cost (두 선의 무게의 곱)의 간선을 그어 플로우 그래프를 만든 뒤 MCMF를 이용하여 문제를 해결하자.

 

간선의 cost의 부호를 뒤집어 계산하면 Maximum Cost Maximum Flow를 계산해낼 수 있다.

 

아래는 제출한 소스코드이다.

#define NODE 802
#define INF 1000000007
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> point;

struct line {
    point A, B;
    ll w;
    line() {};
    line(point A, point B, ll w) {
        this->A = A, this->B = B, this->w = w;
    }
};

int CCW(point A, point B, point C) {
    ll ccw = (B.first - A.first) * (C.second - A.second) - (B.second - A.second) * (C.first - A.first);
    if (ccw > 0) return 1;
    else if (ccw < 0) return -1;
    else return 0;
}

int lineintersectioncheck(line X, line Y) {
    int ccw1 = CCW(X.A, X.B, Y.A);
    int ccw2 = CCW(X.A, X.B, Y.B);
    int ccw3 = CCW(Y.A, Y.B, X.A);
    int ccw4 = CCW(Y.A, Y.B, X.B);

    if (ccw1 == 0 && ccw2 == 0 && ccw3 == 0 && ccw4 == 0) {
        point X1, X2, Y1, Y2;
        if (X.A < X.B) {
            X1 = X.A, X2 = X.B;
        }
        else {
            X1 = X.B, X2 = X.A;
        }
        if (Y.A < Y.B) {
            Y1 = Y.A, Y2 = Y.B;
        }
        else {
            Y1 = Y.B, Y2 = Y.A;
        }
        if (X2 < Y1 || Y2 < X1) return 0;
        else if (X2 == Y1 || Y2 == X1) return 3;
        else return 2;
    }
    else {
        if (ccw1 * ccw2 <= 0 && ccw3 * ccw4 <= 0) {
            return 1;
        }
        else return 0;
    }
}

int source = 0, sink = 801;
int edge[NODE][NODE], cost[NODE][NODE];
vector<int> G[NODE];

int par[NODE];
int stepcost[NODE];
int inque[NODE];

pair<int, int> MCMF() { // {maxflow, mincost}
    int retflow = 0, retcost = 0;
    while (1) {
        memset(par, -1, sizeof(par));
        memset(inque, 0, sizeof(inque));
        fill(stepcost, stepcost + NODE, INF);
        stepcost[source] = 0;

        queue<int> que;
        que.push(source);
        inque[source] = 1;

        while (!que.empty()) {
            int cur = que.front(); que.pop();
            inque[cur] = 0;
            for (auto& nxt : G[cur]) {
                if (edge[cur][nxt] > 0 && stepcost[cur] + cost[cur][nxt] < stepcost[nxt]) {
                    stepcost[nxt] = stepcost[cur] + cost[cur][nxt];
                    par[nxt] = cur;
                    if (!inque[nxt]) {
                        que.push(nxt);
                        inque[nxt] = 1;
                    }
                }
            }
        }

        if (par[sink] == -1) break;

        int flow = INF;
        for (int i = sink; i != source; i = par[i]) flow = min(flow, edge[par[i]][i]);
        for (int i = sink; i != source; i = par[i]) {
            retcost += cost[par[i]][i] * flow;
            edge[par[i]][i] -= flow;
            edge[i][par[i]] += flow;
        }
        retflow += flow;
    }

    return make_pair(retflow, retcost);
}

line lineA[200], lineB[200];

void solve() {
    memset(edge, 0, sizeof(edge));
    memset(cost, 0, sizeof(cost));
    for (auto& v : G) v.clear();

    source = 400, sink = 401;
    int N, M; cin >> N >> M;
    for (int n = 0; n < N; n++) {
        ll x, y, xx, yy, w; cin >> x >> y >> xx >> yy >> w;
        lineA[n] = line(make_pair(x, y), make_pair(xx, yy), w);
    }
    for (int m = 0; m < M; m++) {
        ll x, y, xx, yy, w; cin >> x >> y >> xx >> yy >> w;
        lineB[m] = line(make_pair(x, y), make_pair(xx, yy), w);
    }

    for (int n = 0; n < N; n++) {
        edge[source][n] = 1;
        G[source].emplace_back(n);
        G[n].emplace_back(source);
    }
    for (int m = 0; m < M; m++) {
        edge[m + 200][sink] = 1;
        G[m + 200].emplace_back(sink);
        G[sink].emplace_back(m + 200);
    }

    for (int n = 0; n < N; n++) {
        for (int m = 0; m < M; m++) {
            if (lineintersectioncheck(lineA[n], lineB[m])) {
                ll c = lineA[n].w * lineB[m].w;
                edge[n][m + 200] = 1;
                cost[n][m + 200] = -c;
                cost[m + 200][n] = c;
                G[n].emplace_back(m + 200);
                G[m + 200].emplace_back(n);
            }
        }
    }

    auto p = MCMF();
    cout << p.first << ' ' << -p.second << '\n';
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int T; cin >> T;
    while (T--) {
        solve();
    }
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 18767 // C++] 조교 배치  (0) 2022.08.06
[BOJ 15504 // C++] 프로그래밍 대결  (0) 2022.08.05
[BOJ 20135 // C++] 연세 마스크 공장  (0) 2022.08.03
[BOJ 1127 // C++] 떡국  (0) 2022.08.02
[BOJ 2365 // C++] 숫자판 만들기  (0) 2022.08.01

+ Recent posts