본문 바로가기

알고리즘 관련/BOJ

BOJ)10937 두부 모판 자르기

문제: icpc.me/10937


두부를 1x2 혹은 2x1 모양으로 자르는데 자르는 두부에 써있는 알파벳에 따라 점수를 다르게 받는다고 한다. 이 때 최대 점수를 받도록 두부를 자르는 경우를 출력하는 문제이다.


우리는 두부판을 검은색과 흰색으로 이루어진 체스판으로 생각하면 항상 두부는 검은색 1개 흰색 1개로 매칭된다는걸 알 수 있다.


따라서 우리는 결국 이분 그래프에서의 최대 매칭을 구하면서 그 때의 최대비용을 구해야하는데 매칭이 안되는 경우도 있으니 이분 그래프중 소스에 매칭 되는 부분들을 전부 싱크로 1씩 capacity를 준다.


이후 모든 간선의 capacity를 1로 주고 점수에 맞게 cost를 준뒤 MCMF를 이용하여 maximum cost를 구해내면 된다.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#define INF 987654321
using namespace std;
struct MCMF {
    int n;
    struct Edge {
        int v, cost, cap, rev;
        Edge(int v, int cost, int cap, int rev)
            :v(v), cost(cost), cap(cap), rev(rev) {}
    };
    vector<vector<Edge>> vt;
    void addEdge(int s, int e, int cost, int cap) {
        vt[s].emplace_back(e, cost, cap, vt[e].size());
        vt[e].emplace_back(s, -cost, 0, vt[s].size() - 1);
    }
    vector<int> pv, pe;
    MCMF(int n) :n(n) {
        vt.resize(n + 1);
        pv.assign(n + 1-1);
        pe.assign(n + 1-1);
    }
    bool spfa(int src, int sink) {
        queue<int> qu;
        vector<int> v(n + 10);
        vector<int> dist(n + 1, INF);
        v[src] = 1;
        dist[src] = 0;
        qu.push(src);
        while (qu.size()) {
            int here = qu.front();
            qu.pop();
            v[here] = 0;
            for (int i = 0; i < vt[here].size(); i++) {
                int there = vt[here][i].v;
                int cap = vt[here][i].cap;
                if (cap&&dist[there] > dist[here] + vt[here][i].cost) {
                    dist[there] = dist[here] + vt[here][i].cost;
                    pv[there] = here;
                    pe[there] = i;
                    if (!v[there]) {
                        v[there] = 1;
                        qu.push(there);
                    }
                }
            }
        }
        return dist[sink] != INF;
    }
    int solve(int src, int sink) {
        int cost = 0;
        while (spfa(src, sink)) {
            int minFlow = INF;
            for (int crt = sink; crt != src; crt = pv[crt]) {
                int prev = pv[crt];
                int idx = pe[crt];
                minFlow = min(minFlow, vt[prev][idx].cap);
            }
            for (int crt = sink; crt != src; crt = pv[crt]) {
                int prev = pv[crt];
                int idx = pe[crt];
                vt[prev][idx].cap -= minFlow;
                vt[crt][vt[prev][idx].rev].cap += minFlow;
                cost += vt[prev][idx].cost*minFlow;
            }
        }
        return -cost;
    }
};
int n;
char a[12][12];
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
bool chk(int x, int y) {
    return 0 <= x&&< n && 0 <= y&&< n;
}
int getP(int x, int y, int z, int w) {
    if (a[x][y] > a[z][w]) {
        swap(x, z);
        swap(y, w);
    }
    if (a[x][y] == 'A') {
        if (a[z][w] == 'A')return 100;
        else if (a[z][w] == 'B')return 70;
        else if (a[z][w] == 'C')return 40;
        else return 0;
    }
    else if (a[x][y] == 'B') {
        if (a[z][w] == 'B')return 50;
        else if (a[z][w] == 'C')return 30;
        else return 0;
    }
    else if (a[x][y] == 'C') {
        if (a[z][w] == 'C')return 20;
        else return 0;
    }
    else return 0;
}
int main() {
    scanf("%d"&n);
    for (int i = 0; i < n; i++) {
        getchar();
        for (int j = 0; j < n; j++)
            scanf("%c"&a[i][j]);
    }
    MCMF mcmf(n*+ 3);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if ((i % 2 && j % 2|| (!(i % 2&& !(j % 2))) {
                mcmf.addEdge(n*+ 1, i*+ j, 01);
                mcmf.addEdge(i*+ j, n*+ 201);
                for (int k = 0; k < 4; k++) {
                    int cx = i + dx[k];
                    int cy = j + dy[k];
                    if (!chk(cx, cy))continue;
                    int point = getP(i, j, cx, cy);
                    mcmf.addEdge(i*+ j, cx*+ cy, -point, 1);
                }
            }
            else
                mcmf.addEdge(i*+ j, n*+ 201);
        }
    }
    printf("%d\n", mcmf.solve(n*+ 1, n*+ 2));
    return 0;
}
cs


'알고리즘 관련 > BOJ' 카테고리의 다른 글

BOJ)3747 완벽한 선거!  (0) 2017.03.22
BOJ)8992 집기 게임  (0) 2017.03.20
BOJ)11410 칙칙폭폭  (0) 2017.03.15
BOJ)9413 제주도 관광  (0) 2017.03.13
BOJ)2311 왕복 여행  (0) 2017.03.13