QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#671182 | #900. 一般图最大权匹配 | Qingyyx | WA | 0ms | 7864kb | C++20 | 5.1kb | 2024-10-24 11:31:16 | 2024-10-24 11:31:17 |
Judging History
answer
#include <bits/stdc++.h>
#define ll long long
#define enl putchar('\n')
#define all(x) (x).begin(),(x).end()
#define debug(x) printf(" "#x":%d\n",x);
using namespace std;
const int MAXN = 500 + 5, MAXM = 500 * 500 + 5;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
typedef pair<int, int> pii;
char buf[1 << 21], * p1 = buf, * p2 = buf, obuf[1 << 21], * o = obuf, of[35];
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline ll qpow(ll a, ll n) { ll res = 1; while (n) { if (n & 1)res = res * a % mod; n >>= 1; a = a * a % mod; }return res; }
template <class T = int>inline T read() { T s = 0, f = 1; char c = gc(); for (; !isdigit(c); c = gc())if (c == '-')f = -1; for (; isdigit(c); c = gc())s = s * 10 + c - '0'; return s * f; }
inline void read(int* a, int n) { for (int i = 1; i <= n; ++i)a[i] = read(); }
inline int inal(char* s) { int n = 0; for (s[0] = gc(); !isalpha(s[0]); s[0] = gc()); for (; isalpha(s[n]); s[++n] = gc()); return s[n] = 0, n; }
inline int indi(char* s) { int n = 0; for (s[0] = gc(); !isdigit(s[0]); s[0] = gc()); for (; isdigit(s[n]); s[++n] = gc()); return s[n] = 0, n; }
inline void outd(auto* a, int n) { for (int i = 1; i <= n; ++i)printf("%d ", a[i]); enl; }
int A[MAXN][MAXN], B[MAXN][MAXN], t[MAXN][MAXN], id[MAXN];
// 高斯消元 O(n^3)
// 在传入 B 时表示计算逆矩阵, 传入 nullptr 则只需计算矩阵的秩
void Gauss(int A[][MAXN], int B[][MAXN], int n) {
if (B) {
memset(B, 0, sizeof(t));
for (int i = 1; i <= n; i++) B[i][i] = 1;
}
for (int i = 1; i <= n; i++) {
if (!A[i][i]) {
for (int j = i + 1; j <= n; j++)
if (A[j][i]) {
swap(id[i], id[j]);
for (int k = i; k <= n; k++) swap(A[i][k], A[j][k]);
if (B)
for (int k = 1; k <= n; k++) swap(B[i][k], B[j][k]);
break;
}
if (!A[i][i]) continue;
}
int inv = qpow(A[i][i], mod - 2);
for (int j = 1; j <= n; j++)
if (i != j && A[j][i]) {
int t = (ll)A[j][i] * inv % mod;
for (int k = i; k <= n; k++)
if (A[i][k]) A[j][k] = (A[j][k] - (ll)t * A[i][k]) % mod;
if (B) {
for (int k = 1; k <= n; k++)
if (B[i][k]) B[j][k] = (B[j][k] - (ll)t * B[i][k]) % mod;
}
}
}
if (B)
for (int i = 1; i <= n; i++) {
int inv = qpow(A[i][i], mod - 2);
for (int j = 1; j <= n; j++)
if (B[i][j]) B[i][j] = (ll)B[i][j] * inv % mod;
}
}
bool row_marked[MAXN] = {false}, col_marked[MAXN] = {false};
int sub_n; // 极大满秩子矩阵的大小
// 消去一行一列 O(n^2)
void eliminate(int r, int c) {
row_marked[r] = col_marked[c] = true; // 已经被消掉
int inv = qpow(B[r][c], mod - 2);
for (int i = 1; i <= sub_n; i++)
if (!row_marked[i] && B[i][c]) {
int t = (ll)B[i][c] * inv % mod;
for (int j = 1; j <= sub_n; j++)
if (!col_marked[j] && B[r][j])
B[i][j] = (B[i][j] - (ll)t * B[r][j]) % mod;
}
}
int vertices[MAXN], girl[MAXN]; // girl 是匹配点, 用来输出方案
signed main(signed argc, char const* argv[]) {
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("contrast.out", "w", stdout);
#endif
auto rng = mt19937(chrono::steady_clock::now().time_since_epoch().count());
int n, m;
scanf("%d%d", &n, &m); // 点数和边数
while (m--) {
int x, y;
scanf("%d%d", &x, &y); ++x, ++y;
A[x][y] = rng() % mod;
A[y][x] = -A[x][y]; // Tutte 矩阵
}
for (int i = 1; i <= n; i++)
id[i] = i; // 输出方案用的,因为高斯消元的时候会交换列
memcpy(t, A, sizeof(t));
Gauss(A, nullptr, n);
for (int i = 1; i <= n; i++)
if (A[id[i]][id[i]]) vertices[++sub_n] = i; // 找出一个极大满秩子矩阵
for (int i = 1; i <= sub_n; i++)
for (int j = 1; j <= sub_n; j++) A[i][j] = t[vertices[i]][vertices[j]];
Gauss(A, B, sub_n);
for (int i = 1; i <= sub_n; i++)
if (!girl[vertices[i]])
for (int j = i + 1; j <= sub_n; j++)
if (!girl[vertices[j]] && t[vertices[i]][vertices[j]] && B[j][i]) {
// 注意上面那句 if 的写法, 现在 t 是邻接矩阵的备份,
// 逆矩阵 j 行 i 列不为 0 当且仅当这条边可行
girl[vertices[i]] = vertices[j];
girl[vertices[j]] = vertices[i];
eliminate(i, j);
eliminate(j, i);
break;
}
printf("%d\n", sub_n / 2);
for (int i = 1; i <= n; i++)
if (girl[i] && i < girl[i])printf("%d %d\n", girl[i] - 1, i - 1);
enl;
//=============================================================
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 0
Wrong Answer
time: 0ms
memory: 7864kb
input:
18 120 12 10 6 13 0 10 1 0 6 8 12 5 5 14 3 2 8 1 2 11 5 7 10 1 0 7 7 7 12 2 14 12 3 6 12 10 12 5 5 8 16 5 7 3 5 5 7 10 17 12 7 16 11 2 6 11 9 0 14 2 9 17 8 12 11 2 3 0 9 13 3 7 9 2 5 14 17 9 1 15 3 16 12 3 2 17 7 17 5 2 8 5 1 5 9 7 14 13 5 7 4 1 1 6 6 14 2 7 7 9 5 12 9 10 13 6 3 13 12 2 13 2 7 4 13 ...
output:
9 1 0 3 2 7 4 8 5 11 6 15 9 14 10 17 12 16 13
result:
wrong answer there isn't edge (9, 14)