's profile image

June 17, 2019 23:30

Matroid Intersection

Recall

matroid 에서 는 유한집합, 는 독립집합(independent set)들의 collection이다. 이 때, 는 다음 세 가지 조건을 만족하여야 한다.

  1. 이면 를 만족하는 가 존재

매트로이드는 다양한 집합에서 정의될 수 있다. 그 중 대표적인 예 몇 가지로는 Vector matroid, Graphic matroid, Uniform matroid, Transversal matroid 등이 있다.

의 independent set 에 대해 를 진부분집합으로 갖는 independent set이 없다면 base라고 한다. 모든 base의 크기는 같다.

의 각 부분집합에 대해서 base를 정의한다. 에 대해, 가 independent이고 를 만족하는 independent set 가 존재하지 않는다면 의 base라고 한다. 의 모든 base의 크기는 같다. (base라는 용어를 쓸 때 특정한 집합에 대한 base라는 언급이 있을 때만 집합의 base이고, 그 외의 경우는 matroid의 base이다.)

matroid 에서 rank function 의 부분집합 에서 정의되며, 의 부분집합 중 maximum independent set의 크기이다.

matroid에서 maximum weight independent set은 weight가 큰 원소부터 Greedy하게 삽입하는 알고리즘으로 구할 수 있다.

Matroid Intersection problems

같은 집합 에서 정의된 두 매트로이드 , 가 있을 때, 다음과 같은 문제들을 matroid intersection problem이라 부른다.

문제 1. 의 공통된 base가 존재하는가?

문제 2. 를 만족하는 중 가장 크기가 큰 것을 구하시오. (maximum cardinality common independent set)

문제 3. 의 각 원소에 가중치가 정의되어 있을 때, 를 만족하는 중 원소들의 weight 합이 최대인 것을 구하시오. (maximum weight common independent set)

문제 1은 문제 2의 답을 구하면 바로 해결할 수 있고, 문제 2는 문제 3의 가중치 1인 버전이므로 아래쪽 문제를 해결하면 위쪽 문제는 자동으로 해결됨을 알 수 있다. 이 글에서는 문제 2의 해결방법에 대해 증명과 함께 자세히 다룰 것이고, 문제 3은 문제 2와 비슷한 방법으로 해결되므로 별도의 증명 없이 알고리즘만 제시할 것이다.

Examples

예시 1. 최대 이분 매칭(maximum bipartite matching)

가 bipartition 를 가지는 이분그래프(bipartite graph)일 때,

으로 두면 은 matroid이다.

으로 두면 은 matroid이다.

가 의미하는 바는 가 matching이라는 것이므로, 두 매트로이드의 maximum cardinality common independent set을 구하면(문제 2) 최대 이분 매칭을 구할 수 있다.

예시 2. 최대 가중치 이분 매칭(maximum weight bipartite matching)

예시 2와 똑같이 매트로이드를 구성한 후, 두 매트로이드의 maximum weight common independent set을 구하면(문제 3) 최대 가중치 이분 매칭을 구할 수 있다.

예시 3. vector matroid와 graphic matroid의 intersection

다음과 같은 문제를 생각하자: 의 각 edge에 weight가 정의되어 있다. 의 부분집합 가 cycle을 포함하지 않고, 또한 의 edge의 가중치들의 집합 는 임의의 공집합이 아닌 부분집합을 골랐을 때 원소들을 xor한 값이 0이 되지 않는다고 한다. 이러한 조건을 만족하는 중 크기가 최대인 것을 구하시오.

이 문제는 체 에서 정의된 vector matroid와 graphic matroid의 maximum cardinality common independent set을 구하는 문제이므로, 문제 2로 환원된다.

예시 4. Colorful spanning tree

다음과 같은 문제를 생각하자: 의 각 edge는 1부터 K 범위의 색깔을 가진다. edge 몇 개를 골라 spanning tree를 이루도록 하되, 각 색깔 에 대해 색깔이 인 edge를 최대 개까지만 사용할 수 있다고 하자. 조건을 만족하는 spanning tree가 존재하는지 판별하라.

이 문제는 partition matroid와 graphic matroid의 maximum cardinality common independent set을 구하는 문제이므로, 문제 2로 환원된다. 문제 3을 해결하는 알고리즘을 이용하면 weight가 추가된 그래프에서 minimum weight colorful spanning tree를 구하는 것도 가능하다.

matroid intersection으로 해결 가능한 간단한 4가지 문제를 살펴보았다. 앞의 2문제는 matroid intersection으로 해결하는 것이 확실하게 overkill이지만, 이미 알고 있는 문제도 matroid intersection으로 접근 가능하다는 것을 보여준다. 예시 3, 4는 매우 기본적인 예이며, 좀 더 생각이 필요한 문제들은 문제 2,3을 해결하는 알고리즘을 살펴보고 나서 알아보자.

Finding a maximum cardinality common independent set(문제 2)

앞으로 살펴볼 정리와 증명들에서는 저번 게시물(Introduction to Matroid intersection)에서 살펴본 성질들을 사용하므로, 참고하면 좋다.

정리 1(Strong Base Exchange Theorem). 의 서로 다른 두 base 가 있다. 이 때, 임의의 에 대해 어떤 가 존재하여 , 가 둘 모두 base이다.

Proof: 에서 아무 원소나 골라 라고 하자. 는 base이므로, 는 unique circuit 를 포함한다. 그러면 는 base를 포함한다. 한편, 는 independent set이다. 따라서, 에 포함되면서 를 포함하는 base가 존재한다. 이를 라 하면 어떤 가 존재하여 가 성립한다. (base의 크기는 모두 같으므로)

가 base가 아니라고 가정하자. 그러면 는 어떤 circuit 를 가진다. 이므로 는 두 서로 다른 circuit , 을 가진다. 그런데 base에 원소 하나를 추가하면 unique circuit만을 가지므로 이는 모순이다. 따라서, 는 둘 모두 의 base이다.

따름정리 2. 의 두 independent set 를 만족할 때, 임의의 에 대해 이 존재하여 , 가 둘 모두 independent set이다.

Proof: 라고 하자. 의 원소 중 크기가 이하인 것들의 집합이라고 했을 때 가 matroid인 것은 자명하다. 또한 의 모든 independent set의 크기가 이하이므로 , 의 base이다. 따라서, Strong Base Exchange Theorem에 의해 따름정리 2가 성립한다.

정의 1. matroid 에서 independent set 에 대해 directed bipartite graph 를 다음과 같이 정의하자: , . 의 bipartition은 이다.

보조정리 3. 의 두 independent set 를 만족할 때, 에서 perfect matching을 갖는다. (단, )

Proof: 에 대한 수학적 귀납법으로 증명할 것이다. 이면 자명하다. 인 경우, 따름정리 2에 의해 , 가 존재하여 가 independent set이다. 이 떄, 이고 이므로, 수학적 귀납법에 의해 에서 perfect matching 을 갖는다. 그러면 에서의 perfect matching이다.

정리 4. 의 independent set 의 부분집합 를 만족한다. 이 때, 에서 unique perfect matching을 가지면 는 independent set이다.

다음과 같은 성질을 이용하면 정리 4를 증명할 수 있다.

성질 5. 는 bipartition 를 가지는 bipartite graph이다. 가 unique perfect matching 을 가질 때, 다음 조건을 만족하도록 의 원소들을 , 의 원소들을 로 라벨링하는 것이 가능하다:

조건: 이고, 모든 에 대해 를 만족한다.

성질 5의 경우 증명이 간단하지 않아 생략한다. 그러나 이분 그래프의 perfect matching에서 중요한 성질 중 하나이므로 알아두면 좋을 것이다. 그러면 이제 성질 5를 이용해 정리 4를 증명해보자.

Proof: 그래프 에서 에 포함되는 vertex들과 그 vertex 사이의 간선만 남긴 그래프를 라 하자 ( : subgraph of induced by ). 는 bipartite graph 이므로 [성질 5]에 의해 의 vertex들을 , 의 vertex들을 로 라벨링하여 이고 , 가 성립하도록 할 수 있다.

에서 unique perfect matching을 가지는데 가 independent set이 아니라고 하자. 의 circuit이다. 가 성립하는 가장 작은 수라고 하자. 이면 이므로 가 성립한다. 의 임의의 원소 의 원소이거나 어떤 에 대해 가 성립하므로 가 성립한다 (의 원소 및 에 추가했을 때 dependent한 원소들의 집합이다). 는 circuit이므로, 가 성립한다. 따라서 인데, 이는 , 즉 가 independent하다는 사실에 모순이다. 따라서, 는 independent set이다.

그러면 이제 두 매트로이드에서 가장 큰 common independent set을 구할 준비를 마쳤다.

정리 5. , 가 각각 rank function 를 가진다고 하자. 이 때 두 매트로이드에서 가장 큰 common independent set의 크기는 (size of maximum cardinality set in ) 다음과 같다:

Proof: , 에 대해 , 이므로 이므로 한쪽 부등식이 증명되었다. 반대방향의 부등식은 실제로 어떤 에 대해 크기의 matroid intersection을 찾는 알고리즘을 제시하여 증명할 것이다. 이 알고리즘은 이분 매칭에서 augmenting path를 찾는 방법과 비슷하게 크기를 늘려가는 방법을 사용한다. 즉, 가 주어지면 을 만족하는 를 찾거나 아니면 그러한 가 없다는 것을 의 크기가 어떤 에 대해 와 같다는 것을 이용하여 보인다. 이 증명을 위해서는 몇 가지 준비가 더 필요하다:

정의 6. where . 다르게 말하면, 의 reverse의 union이다.

, 라 하자. 에서 에서 출발해 에서 끝나는 경로 중 최소 길이인 것을 라 하자. (는 존재하지 않을 수도 있다)

보조정리 7. 만약 가 존재하지 않는다면 ( 에서 에서 로 가는 path가 없다면 ) 의 maximum cardinality set이다.

Proof: 이나 가 빈 집합이라면 는 두 매트로이드 중 하나의 base이므로 maximum cardinality set임이 자명하다. 라 하자. 에 도달할 수 있는 vertex들의 집합이라 하면 에서 로 가는 path가 없으므로 이다. 이제 , 임을 보이면 앞서 모든 에 대해 가 성립함을 보였으므로 의 maximum cardinality set임을 보일 수 있다.

claim 1.

Proof: 이면 가 존재하여 을 만족한다. 만약 이면 , , 이므로 모순이다. 그렇지 않다면 , 이므로 가 존재하여 이 성립한다. 그러나 이 경우 이고, 이므로 를 거쳐 에 도달할 수 있어서 이여 하는데 이는 에 모순이다. 따라서, .

claim 2. : claim 1과 유사하게 증명 가능하다.

claim 1, 2가 증명되었으므로, 에서 에서 로 가는 path가 없다면 의 maximum cardinality set이다.

정리 8. 에서 로 가는 최소 길이의 path 에 대해, 이다. 또한, 이다.

Proof: 는 bipartite graph 에서 로부터 시작해 로 끝나는 경로이므로 에서 에 포함되는 원소보다 에 포함되는 원소가 항상 하나 더 많다. 따라서 이 성립한다. 라 두자(). 집합 에 대해 , 이고 로 가는 간선들은 에서 로 가는 unique perfect matching을 이룬다 (matching이 존재함은 자명하고, unique하지 않다면 [성질 5]에 의해 인 간선 가 존재하는데 이는 가 shortest path임에 모순이다). 따라서, 정리 4에 의해 .

모든 에 대해 가 성립하므로 이고, 따라서 이다. 이므로 가 존재하여 인데, 인 경우 이면 인 것에 모순이므로 일 수밖에 없다. 즉, 이다. 마찬가지 방법으로 임도 쉽게 보일 수 있다 (에 대해 같은 방법을 쓰면 된다). 따라서, .

앞서 증명한 정리들로 얻을 수 있는 최종 결과는 다음과 같다.

정리 9. 다음 알고리즘은 두 matroid의 intersection 내 maximum cardinality set을 다항 시간 내에 올바르게 구한다.

Step 1. 로 초기화한다.

Step 2. 를 만들고, 집합 , 를 구하자.

Step 3. 에서 로 가는 shortest path 를 구한다.

Step 4. 만약 가 존재하지 않으면 가 maximum cardinality set이므로 를 리턴하고 종료한다. 그렇지 않으면 를 대입한 뒤 Step 2로 돌아간다.

Finding a maximum weight common independent set(문제 3)

정리 9를 다시 한번 살펴보자.

정리 9. 다음 알고리즘은 두 matroid의 intersection 내 maximum cardinality set을 다항 시간 내에 올바르게 구한다.

Step 1. 로 초기화한다.

Step 2. 를 만들고, 집합 , 를 구하자.

Step 3. 에서 로 가는 shortest path 를 구한다.

Step 4. 만약 가 존재하지 않으면 가 maximum cardinality set이므로 를 리턴하고 종료한다. 그렇지 않으면 를 대입한 뒤 Step 2로 돌아간다.

위 알고리즘에서 shortest path P를 구할 때, maximum cardinality set에서는 그냥 모든 간선의 길이를 1로 두고 shortest path를 구했지만, weighted case에서는 에 대해 의 weight를 , 에 대해 weight를 로 assign한 후 에서 로 가는 path 중 minimum length path ( 내 정점의 weight 합이 최소가 되는 path)로 잡고, 그런 것이 여러 개 있다면 그 중에서 가장 적은 edge를 지나는 path를 로 두어야 한다. 즉, 새로 만들어진 의 weight이 최대가 되는 path 중 가장 적은 개수의 edge를 지나는 path를 로 두는 것이다. 그 부분만 수정을 해 주면 알고리즘이 리턴하는 최종 에서 가장 weight가 큰 set이 된다. 또한, matroid에서 maximum weighted independent set을 구할 때와 마찬가지로, 각 step 2~4를 반복하면서 얻는 들은 크기가 와 같은 intersection 중에서는 weight가 maximum인 set이다. (자세한 증명은 생략한다)

문제 풀이

SWERC 2011. Coin Collecting (https://www.acmicpc.net/problem/3836)

문제를 간단하게 설명하자면 다음과 같다: N쌍의 봉투가 있고 각각의 봉투에는 서로 다른 종류의 두 동전이 있다. 이때 각각의 쌍에서 최대 하나의 봉투만을 골라 총 N개 이하의 봉투를 고르려고 한다. 이 때 지켜야 할 조건이 있는데, 고른 봉투 중 1개 이상을 선택하여 선택한 봉투들에 들어 있는 동전만 놓고 보았을 때 모든 종류의 동전이 짝수개가 되도록 선택하는 방법이 존재하지 않도록 봉투를 고르려고 한다. 최대한 많은 개수의 동전을 모으는 것이 목표일 때, 최대 몇 개까지 가능한가?

이 문제는 결국 각각의 동전 종류를 vertex로, 각각의 봉투를 edge로 치환하면 edge쌍 N개가 주어질 때 각 쌍에서 최대 하나의 edge만을 선택하여 forest가 되도록 할 때, 선택한 edge의 개수를 최대화하는 문제가 된다. 이렇게 그래프 문제로 치환을 해 놓으면 이것은 partition matroid와 graphic matroid의 intersection에서 maximum independent set을 구하는 문제임을 쉽게 관찰할 수 있다.

다음은 이 문제의 AC 코드이다 (주의 : 이 문제는 시간 제한이 넉넉하지 않아 코드에 matroid intersection의 핵심이 아닌 부분이 다수 존재하므로 다음 문제의 코드를 읽는 것이 더 나을 수 있음)

#include<cstdio>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
#define N_ 610
using namespace std;
map<int, int>Map;
int m, n, chk[N_ * 2], vis[N_], UF[N_ * 2], CK1[N_], CK2[N_], Q[N_], Path[N_];
bool vv[N_ * 2], inTP[N_ * 2];
bool E[N_][N_];
vector<int> G[N_ * 2], TP;
struct Edge {
	int a, b;
}w[N_];
int Num(int a) {
	if (!Map.count(a))Map[a] = ++n;
	return Map[a];
}
void PushTP(int a) {
	if (!inTP[a]) {
		TP.push_back(a);
		inTP[a] = 1;
	}
}
void Del_Edge(int a, int b) {
	PushTP(a);
	PushTP(b);
	G[a].erase(find(G[a].begin(), G[a].end(), b));
	G[b].erase(find(G[b].begin(), G[b].end(), a));
}
void Add_Edge(int a, int b) {
	PushTP(a);
	PushTP(b);
	G[a].push_back(b);
	G[b].push_back(a);
}
void Make(int x) {
	while (1) {
		Add_Edge(w[x].a, w[x].b);
		chk[x] = 1;
		if (Path[x] == -1)break;
		Del_Edge(w[Path[x]].a, w[Path[x]].b);
		chk[Path[x]] = 0;
		x = Path[Path[x]];
	}
}
void DFS(int a, int r) {
	vv[a] = 1;
	UF[a] = r;
	for (auto &x : G[a]) {
		if (!vv[x])DFS(x, r);
	}
}
void Build() { // 정리 9의 알고리즘에서 step 2. 그래프를 만드는 부분.
	int i;
	memset(vv, 0, (n + 1));
	memset(inTP, 0, (n + 1));
	for(auto &t : TP){
		if (!vv[t])DFS(t, t);
	}
	TP.clear();
}
bool Go() { // 정리 9의 알고리즘
	int i, j;
	memset(E, 0, sizeof(E));
	for (i = 0; i < m; i++) {
		Path[i] = -1;
		CK1[i] = CK2[i] = 0;
		vis[i] = 0;
	}
	Build();
	for (j = 0; j < m; j++) {
		if (chk[j])continue;
		if (UF[w[j].a] != UF[w[j].b])CK2[j] = 1;
	}
	for (j = 0; j < m; j++) {
		if (!chk[j]) {
			if (!chk[j^1])CK1[j] = 1;
			continue;
		}
		Del_Edge(w[j].a, w[j].b);
		Build();
		chk[j] = 0;
		for (i = 0; i < m; i++) {
			if (chk[i])continue;
			if (UF[w[i].a] != UF[w[i].b])E[i][j] = 1;
			if (!chk[i^1]) {
				E[j][i] = 1;
			}
		}
		chk[j] = 1;
		Add_Edge(w[j].a, w[j].b);
	}
	int head = 0, tail = 0;
	for (i = 0; i < m; i++) {
		if (CK1[i]) {
			Q[++tail] = i;
			vis[i] = 1;
			if (CK2[i]) {
				Make(i);
				return true;
			}
		}
	}
	while (head < tail) { // BFS를 통해 X1-X2 shortest path를 찾는다.
		int x = Q[++head];
		for (int y = 0; y < m; y++) {
			if (E[x][y] && !vis[y]) {
				Q[++tail] = y;
				vis[y] = 1;
				Path[y] = x;
				if (CK2[y]) {
					Make(y);
					return true;
				}
			}
		}
	}
	return false;
}
void Solve() {
	int i, a, b, res = 0;
	Map.clear();
	TP.clear();
	n = 0;
	m *= 2;
	for (i = 0; i < m; i++) {
		scanf("%d%d", &a, &b);
		a = Num(a), b = Num(b);
		w[i] = { a,b };
	}
	for (i = 1; i <= n; i++) {
		UF[i] = i;
		G[i].clear();
	}
	for (i = 0; i < m; i++) chk[i] = 0;


	for (int i = 0; i < m; ++i) {
		Build();
		if (!chk[i ^ 1] && UF[w[i].a]!=UF[w[i].b]) {
			Path[i] = -1;
			Make(i);
			res += 2;
		}
	}

	while (Go())res+=2;
	printf("%d\n", res);
}
int main() {
	srand(1879);
	while (1) {
		scanf("%d", &m);
		if (!m)break;
		Solve();
	}
}
NAIPC 2018 G. Rainbow Graph

이 문제는 앞선 문제와 달리 matroid intersection 알고리즘을 완벽하게 이해했더라도 풀기 쉽지 않고, 생각할 거리가 있는 문제이므로 만약 알고리즘을 이해했다면 혼자 풀어보려고 시도해보는 편이 좋다.

문제의 간단한 설명은 다음과 같다: 그래프 의 각 edge에는 R, G, B의 3가지 색깔 및 가중치가 있다. 이 때, 정확히 개의 edge를 골라 edge들 중 색깔이 R 또는 G 인것만 남겨도 가 connected이고, edge들 중 색깔이 G 또는 B인 것만 남겨도 가 connected가 되도록 개의 edge를 고르려고 한다. 고르는 경우가 여러 방법이 있다면 그 중 고른 edge들의 weight 합이 최소가 되도록 고르고자 한다. 이 때, 모든 부터 까지의 모든 에 대해 이 문제를 해결하시오 (불가능하면 -1, 가능하면 최소 weight 합을 출력한다).

이전 글 Introduction to matroid에서 graphic matroid를 소개할 때, edge들이 forest를 이루도록 하는 일반적인 graphic matroid만 설명한 것이 아니라 변형된 몇 가지 graphic matroic를 소개하였다. 그 중 하나가 바로 이 문제에 사용되는 매트로이드인데, 가 무향 연결 그래프일 때, 로 두면 는 matroid이다. 이 문제를 풀기 위해 이를 살짝 변형해보자. 가 무향 연결 그래프일 때, 로 두면 는 matroid이다. 로 두면 는 matroid이다.

주어진 에 대해, 두 matroid의 intersection 에서 크기가 인 것들 중 maximum weighted set을 구하면 그 여집합이 답이 됨을 쉽게 알 수 있다. 그럼 이제 [문제 3]을 해결하는 알고리즘을 이용하면 이 문제를 해결할 수 있다.

다음은 이 문제의 AC 코드이다.

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int n, m, Res[110], used[110];
struct Edge{
    int a, b, c;
    char ch;
}w[110];

struct DSU{ //union find
    int UF[110];
    void init(){
        for(int i=1;i<=n;i++)UF[i]=i;
    }
    int Find(int a){
        if(a==UF[a])return a;
        return UF[a] = Find(UF[a]);
    }
    bool Merge(int a, int b){
        a=Find(a),b=Find(b);
        if(a==b)return false;
        UF[a]=b;
        return true;
    }
    bool ok(const char *ch){
        init();
        int i, com = n;
        for(i=0;i<m;i++){
            if(used[i]){
                if(w[i].ch == ch[0] || w[i].ch == ch[1]){
                    if(Merge(w[i].a,w[i].b))com--;
                }
            }
        }
        return com == 1;
    }
}RG, GB;

struct Graph{
    vector<int>E[110], L[110];
    int D[110], inQ[110], Q[101000], Path[110];
    void init(){
        for(int i=0;i<=m+2;i++)E[i].clear(),L[i].clear();
    }
    void Add_Edge(int a, int b, int c){
        E[a].push_back(b);
        L[a].push_back(c);
    }
    bool SPFA(){ //find minimum length path from X1 to X2
        int i, head = 0, tail = 0;
        for(i=0;i<=m+2;i++)D[i]=1e9, inQ[i] = 0;
        D[m] = 0; Q[++tail] = m, inQ[m] = 1;
        while(head < tail){
            int x = Q[++head];
            inQ[x] = 0;
            for(i=0;i<E[x].size();i++){
                if(D[E[x][i]] > D[x] + L[x][i]){
                    D[E[x][i]] = D[x] + L[x][i];
                    Path[E[x][i]] = x;
                    if(!inQ[E[x][i]]){
                        inQ[E[x][i]] = 1;
                        Q[++tail] = E[x][i];
                    }
                }
            }
        }
        if(D[m+1] > 8e8)return false;
        int x = m+1;
        while(x!=m){
            if(x<m)used[x] = !used[x];
            x = Path[x];
        }
        return true;
    }
}GG;

bool Do(){
    int i, j;
    GG.init();
    for(i=0;i<m;i++){ //make graph GG
        if(used[i]){
            used[i] = 0;
            if(RG.ok("RG"))GG.Add_Edge(m,i,-w[i].c*1000+1);
            if(GB.ok("GB"))GG.Add_Edge(i,m+1,1);
            used[i] = 1;
        }
        for(j=0;j<m;j++){
            if(!used[i] && used[j]){
                used[i] = 1, used[j] = 0;
                if(RG.ok("RG"))GG.Add_Edge(i,j,-w[j].c * 1000 +1);
                if(GB.ok("GB"))GG.Add_Edge(j,i,w[i].c*1000 + 1);
                used[i] = 0, used[j] = 1;
            }
        }
    }
    if(!GG.SPFA())return false;
    return true;
}

int main(){
    int i, j;
    char pp[3];
    scanf("%d%d",&n,&m);
    for(i=0;i<m;i++){
        scanf("%d%d%d%s",&w[i].a,&w[i].b,&w[i].c, pp);
        w[i].ch = pp[0];
    }
    for(i=1;i<=m;i++){
        Res[i] = -1;
        used[i-1] = 1;
    }

    if(RG.ok("RG") && GB.ok("GB")){
        Res[m] = 0;
        for(i=0;i<m;i++){
            Res[m] += w[i].c;
        }
        for(i=m-1;i>=1;i--){
            if(!Do())break;
            Res[i] = 0;
            for(j=0;j<m;j++)if(used[j])Res[i] += w[j].c;
        }
    }
    for(i=1;i<=m;i++)printf("%d\n",Res[i]);
}

요약

두 글에 걸쳐서 matroid 및 matroid intersection에 대해 알아보았다. 저번 글에서는 matroid의 개념, 예시 및 관련 용어(base, rank function) 등에 대해 간략히 소개하고 maximum weight independent set을 구하는 알고리즘 및 그 정당성을 자세하게 설명하였다. 본 글에서는 두 matroid의 common independent set 중 크기가 가장 큰 것, 가중치가 주어졌을 때는 최대 가중치를 가지는 것을 구하는 알고리즘을 증명과 함께 제시하였다. 그리고 두 글 모두 제시한 알고리즘을 이용해 풀어 볼 수 있는 문제를 여러 가지 제시하였다. Problem solving에서는 matroid 관련 문제가 그렇게 자주 나오지는 않지만, matroid에 관한 재미있는 사실은 많이 있으니 관심이 있는 사람들은 찾아보는 것을 추천한다.