luogu P4100 [HEOI2013]钙铁锌硒维生素
https://www.luogu.com.cn/problem/P4100
题目大意:
首先构造两个矩阵A,B
把A,B转置一下变成
A
T
,
B
T
A^T,B^T
AT,BT
就相当于是写成把若干个向量拼成矩阵的形式
然后可以得到
B
=
R
A
B=RA
B=RA保证
R
[
i
]
[
j
]
!
=
0
R[i][j]!=0
R[i][j]!=0才能让
A
[
i
]
A[i]
A[i]用
B
[
j
]
B[j]
B[j]代替,不然说明
B
[
j
]
B[j]
B[j]会与除了
A
[
i
]
A[i]
A[i]外的向量线性相关
所以
R
=
B
A
−
1
\large R=BA^{-1}
R=BA−1
具体做的话可以在
A
A
A后面接一个伴随矩阵
B
B
B然后把
A
A
A消元成单位矩阵,这时候
B
B
B就变成
R
R
R了
再根据
R
R
R连边跑最大匹配(字典序最小的)即可
code:
#include<bits/stdc++.h>
#define N 605
using namespace std;
const double eps = 1e-9;
int vis[N], match[N], n;
double a[N][N], b[N][N];
int dfs(int u) {
for(int v = 1; v <= n; v ++) if(!vis[v] && fabs(b[u][v]) > eps) {
vis[v] = 1;
if(!match[v] || dfs(match[v])) {
match[v] = u;
return 1;
}
}
return 0;
}
int dfss(int u, int fr) {
for(int v = 1; v <= n; v ++) if(!vis[v] && fabs(b[u][v]) > eps) {
vis[v] = 1;
if(match[v] == fr || (match[v] > fr && dfss(match[v], fr))) {
match[v] = u;
return v;
}
}
return 0;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
scanf("%lf", &a[j][i]);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
scanf("%lf", &b[j][i]);
for(int i = 1; i <= n; i ++) {
int j = i;
for(int k = i + 1; k <= n; k ++) if(fabs(a[k][i]) > fabs(a[j][i])) j = k;
if(j != i) swap(a[i], a[j]), swap(b[i], b[j]);
double x = a[i][i];
if(fabs(x) < eps) { printf("NIE"); return 0;}
for(int j = 1; j <= n; j ++) a[i][j] /= x, b[i][j] /= x;
for(int j = 1; j <= n; j ++) if(j != i) {
double t = a[j][i];
for(int k = 1; k <= n; k ++) {
a[j][k] -= a[i][k] * t;
b[j][k] -= b[i][k] * t;
}
}
}
// for(int i = 1; i <= n; i ++) {
// for(int j = 1; j <= n; j ++) printf("%.3lf ", b[i][j]); printf("\n");
// }
for(int i = 1; i <= n; i ++) {
memset(vis, 0, sizeof vis);
if(!dfs(i)) { printf("NIE"); return 0;}
}
// for(int i = 1; i <= n; i ++) printf(" %d ", match[i]); printf("\n");
puts("TAK");
for(int i = 1; i <= n; i ++) {
memset(vis, 0, sizeof vis);
printf("%d\n", dfss(i, i));
}
return 0;
}