※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 15504번 문제인 프로그래밍 대결이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/15504
15504번: 프로그래밍 대결
온조는 N명의 참가자가 참가하는 프로그래밍 대결 대회를 열 것이다. 이 대회는 두 참가자가 일대일로 붙는 N-1개의 대결로 이루어진다. i번째 참가자는 실력 Ai를 가지고 있어 두 참가자가 대결
www.acmicpc.net
두 참가자가 대결하면 실력이 더 낮은 참가자는 떨어지고 최종적으로 한 사람이 남을 때까지 대결을 이어가므로, 실력이 가장 좋은 참가자를 제외한 모든 참가자 i는 자신보다 실력이 좋은 참가자와 정확히 한 번 대결하고 자신보다 실력이 나쁜 참가자와 Li - 1번 이하로 대결하게 된다.
각 참가자마다 그 자신보다 실력이 더 좋은 참가자를 제약에 맞춰 선택해 경쟁하되 그 모든 경우중 대회의 재미를 최대화하는 것은 MCMF를 이용해 구해낼 수 있다. 그래프를 잘 모델링해 값을 구해내자.
실력이 가장 좋은 참가자의 경우 자신보다 실력이 나쁜 참가자와 Li번 대결할 수 있음에 유의하자.
글쓴이의 경우 아래 코드의 82, 89번 라인에서 xor연산보다 -연산의 우선순위가 더 높은 것을 간과해 디버깅이 오래 걸렸다. 비트연산을 사용할 경우 연산의 우선순위에 유의하여 구현하자.
아래는 제출한 소스코드이다.
#define NODE 602
#define INF 1000000007
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
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);
}
int A[301];
int H[301];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
source = 0, sink = 601;
int N; cin >> N;
int AMax = -1, AMaxidx = -1;
for (int n = 1; n <= N; n++) {
int& x = A[n]; cin >> x;
if (x > AMax) AMax = x, AMaxidx = n;
}
for (int n = 1; n <= N; n++) cin >> H[n];
for (int n = 1; n <= N; n++) {
edge[source][n] = 1;
G[source].emplace_back(n);
G[n].emplace_back(source);
for (int m = n + 1; m <= N; m++) {
if (A[n] < A[m]) {
edge[n][m + 300] = 1;
cost[n][m + 300] = -((A[n] ^ A[m]) - H[n] - H[m]);
cost[m + 300][n] = -cost[n][m + 300];
G[n].emplace_back(m + 300);
G[m + 300].emplace_back(n);
}
else {
edge[m][n + 300] = 1;
cost[m][n + 300] = -((A[m] ^ A[n]) - H[m] - H[n]);
cost[n + 300][m] = -cost[m][n + 300];
G[m].emplace_back(n + 300);
G[n + 300].emplace_back(m);
}
}
}
for (int n = 1; n <= N; n++) {
int c; cin >> c;
if (n == AMaxidx) edge[n + 300][sink] = c;
else edge[n + 300][sink] = c - 1;
G[n + 300].emplace_back(sink);
G[sink].emplace_back(n + 300);
}
cout << -MCMF().second;
}
'BOJ' 카테고리의 다른 글
[BOJ 2145 // C++] 숫자 놀이 (0) | 2022.08.07 |
---|---|
[BOJ 18767 // C++] 조교 배치 (0) | 2022.08.06 |
[BOJ 8992 // C++] 집기 게임 (0) | 2022.08.04 |
[BOJ 20135 // C++] 연세 마스크 공장 (0) | 2022.08.03 |
[BOJ 1127 // C++] 떡국 (0) | 2022.08.02 |