baekjoon

[백준] 11408 열혈강호 5

윤만석 2023. 3. 28. 14:59

문제

강호네 회사에는 직원이 N명이 있고, 해야 할 일이 M개가 있다. 직원은 1번부터 N번까지 번호가 매겨져 있고, 일은 1번부터 M번까지 번호가 매겨져 있다.

각 직원은 한 개의 일만 할 수 있고, 각각의 일을 담당하는 사람은 1명이어야 한다.

각각의 직원이 할 수 있는 일의 목록과 그 일을 할 때 강호가 지급해야 하는 월급이 주어졌을 때, M개의 일 중에서 최대 몇 개를 할 수 있는지, 그리고 그 때 강호가 지불해야 하는 월급의 최솟값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 직원의 수 N과 일의 개수 M이 주어진다. (1 ≤ N, M ≤ 400)

둘째 줄부터 N개의 줄의 i번째 줄에는 i번 직원이 할 수 있는 일의 개수와 할 수 있는 일의 번호와 그 일을 할 때 지급해야 하는 월급이 주어진다. 월급은 10,000보다 작거나 같은 자연수 또는 0이다.

출력

 

첫째 줄에 강호네 회사에서 할 수 있는 일의 개수를 출력한다.

둘째 줄에는 강호가 지급해야 하는 월급의 최솟값을 출력한다.

 

 

Minimum Cost Maximum flow 문제입니다.

각 간선의 capacity는 1 입니다.

따라서 flow는 최대 1밖에 될 수 없습니다.

직원>>일 로 가는 cost는 주어지지만, source에서 직원으로, 일에서 sink로 가는 cost는 항상 0입니다

따라서 MCMF를 이용해서 가장 적은 비용이 드는 간선으로 1씩 흘려보내면 답을 구할 수 있습니다.

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false),cin.tie(NULL);
#define mset(v) memset(v,0,sizeof(v));
#define rep(i,a) for(int i=0;i<a;++i)
#define REP(i,a) for(int i=1;i<=a;++i)

using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
typedef tuple<int, int, int>ti;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
int dy[] = { -1,0,1,0 }, dx[] = { 0,1,0,-1 };
int N, M, S = 801, E = 802;
int c[803][803], f[803][803], cost[803][803], n, a, b, INF = 987654321, ans, cnt;
vi adj[803];
//1~400 : 사람  401~800 : 일 801:소스 802:싱크
int main() {
	FAST;
	cin >> N >> M;
	REP(i, N) {
		c[S][i] = 1;
		adj[i].push_back(S);
		adj[S].push_back(i);
	}
	for (int i = 401; i <= 400 + M; i++) {
		c[i][E] = 1;
		adj[i].push_back(E);
		adj[E].push_back(i);
	}
	REP(i, N) {
		cin >> n;
		while (n--) {
			cin >> a >> b;
			adj[i].push_back(400 + a);
			adj[400 +a].push_back(i);
			cost[i][400+a] = b;
			cost[400+a][i] = -b;
			c[i][400 + a] = 1;
		}
	}

	while (1) {
		int parent[803], dist[803], inQ[803];
		mset(inQ);
		fill(dist, dist + 803, INF);
		fill(parent, parent + 803, -1);
		queue<int>q;
		q.push(S);
		dist[S] = 0;
		inQ[S] = 1;
		while (!q.empty()) {
			int cur = q.front();
			q.pop();
			inQ[cur] = 0;
			for (auto next : adj[cur]) {
				if (c[cur][next]-f[cur][next] > 0 && dist[next] > dist[cur] + cost[cur][next]) {
					dist[next] = dist[cur] + cost[cur][next];
					parent[next] = cur;
					if (!inQ[next]) {
						inQ[next] = 1;
						q.push(next);
					}
				}
			}
		}
		if (parent[E] == -1) {
			break;
		}
		int flow = 1;
		for (int i = E; i != S; i = parent[i]) {
			f[parent[i]][i] = flow;
			f[i][parent[i]] = -flow;
			ans += cost[parent[i]][i];
		}
		cnt++;
	}
	cout <<cnt<<"\n"<< ans;
}