【题目链接】
【思路要点】
- 首先我们需要了解一下“稳定婚姻问题”。
- 给出\(N\)个男孩,\(N\)个女孩。
每个男孩对所有女孩有一个序关系,表示他对女孩的喜好程度。
每个女孩也对所有男孩有一个序关系,表示她对男孩的喜好程度。- 定义一个稳定匹配为满足下列性质的完备匹配:
不存在一个男孩和一个女孩,他们没有配对,但互相喜欢对方胜过自己的配偶。- 稳定匹配一定存在。下面给出一种\(O(N^2)\)寻找稳定匹配的算法。
- 每轮任选一个还未匹配的男孩,令其向还未求婚过的他最喜欢的女孩求婚。
如果那个女孩还没有配偶,或者喜欢当前男孩胜过自己的配偶,那么她就会同意此次求婚,否则会拒绝。
直至所有男孩都有配偶。- 该算法能够确保找到一个稳定匹配。
- 本题中,我们把行看做男孩,数看做女孩。
- 行喜欢在这行靠前的数,数喜欢她出现的靠后的行。
- 时间复杂度\(O(TNM)\)。
- 注:在BZOJ上提交时请确保你的程序不会输出任何东西。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 205; const int MAXM = 405; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int a[MAXN][MAXM]; int ans[MAXN], bns[MAXN], cnt[MAXN]; int List[MAXN][MAXN], rank[MAXN][MAXN]; bool func(int x, int y) { return rank[y][x] > rank[y][bns[y]]; } int main() { int T; read(T); while (T--) { int n, m; read(n), read(m); for (int i = 1; i <= n; i++) { int tmp = 0; for (int j = 1; j <= m; j++) { read(a[i][j]); if (a[i][j]) List[i][++tmp] = a[i][j]; } } memset(cnt, 0, sizeof(cnt)); for (int j = m; j >= 1; j--) for (int i = 1; i <= n; i++) { if (a[i][j] == 0) continue; rank[a[i][j]][i] = ++cnt[a[i][j]]; } memset(ans, 0, sizeof(ans)); memset(bns, 0, sizeof(bns)); static int q[MAXN * MAXN]; int l = 1, r = n; for (int i = 1; i <= n; i++) { cnt[i] = 1; q[i] = i; } while (l <= r) { int tmp = q[l++]; while (bns[List[tmp][cnt[tmp]]] != 0 && func(tmp, List[tmp][cnt[tmp]])) cnt[tmp]++; if (bns[List[tmp][cnt[tmp]]] == 0) { ans[tmp] = List[tmp][cnt[tmp]]; bns[List[tmp][cnt[tmp]]] = tmp; } else { ans[tmp] = List[tmp][cnt[tmp]]; q[++r] = bns[List[tmp][cnt[tmp]]]; ans[bns[List[tmp][cnt[tmp]]]] = 0; bns[List[tmp][cnt[tmp]]] = tmp; } } for (int i = 1; i <= n; i++) printf("%d ", ans[i]); printf("\n"); } return 0; }