【BZOJ】3168: [Heoi2013]钙铁锌硒维生素
题解
显然我们既然初始矩阵就能通过线性变换变成单位矩阵,则该矩阵一定有逆
没有逆输出NIE
而且因为这些向量两两正交,则表示一个向量的时候表示方法唯一
那么我们求一个逆可以求出这个矩阵消成单位矩阵的线性表示,再拿第二个矩阵和逆矩阵相乘可以得到第二个矩阵每个行向量用第一个矩阵的行向量唯一的表示方法
如果第二套的第k个行向量的表示里第一行h个行向量系数不为0,则h可以被k替代
建图二分图匹配,先求一个匹配出来,然后对于每个点从前往后固定匹配看看能不能使得靠前的更小
说的很高端吧
算了我简单一点说
就是一考虑初始的矩阵,什么两三行加加减减乘个系数,是可以消成单位1的,这个可以用类似高斯消元的方法解决,实际上如果你了解矩阵求逆的话你就知道我在给这个矩阵求逆矩阵
如果消不成就是NIE了
如果你不了解的话,你可以把每次变换每个行所用到的系数记下来,变成另一个矩阵\(B\)
那么我们考虑第二套的某个向量,
\((b_{1},b_{2}...b_{n}) = \sum_{i = 1}^{n} c_{i} (a_{1},a_{2}..a_{n})\)
显然如果\(c_{i}\)有数的话,我门可以把\(c_{i}\)移到等号左边,把第二套的这个向量移到等式右边,就证明\(i\)可以被这个向量换掉了
这个系数可以用两个矩阵相乘求出来
图建出来了,那就是跑二分图了
我们先求出一个完备匹配来,没有就是NIE,有的话对于\(1-n\)从小到大枚举能更新的匹配点,然后把这个点强制不选再跑二分图看看会不会合法
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 305
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N;
int g[305][305],matc[305],matk[305];
bool vis[305];
bool flag = 0;
struct Matrix {
db f[305][305];
Matrix() {memset(f,0,sizeof(f));}
void unit() {
for(int i = 1 ; i <= N ; ++i) {
f[i][i] = 1.0;
}
}
friend Matrix operator * (const Matrix &a,const Matrix &b) {
Matrix c;
for(int i = 1 ; i <= N ; ++i) {
for(int j = 1 ; j <= N ; ++j) {
for(int k = 1 ; k <= N ; ++k) {
c.f[i][j] += a.f[i][k] * b.f[k][j];
}
}
}
return c;
}
friend Matrix operator ~(Matrix a) {
Matrix b;
b.unit();
for(int i = 1 ; i <= N ; ++i) {
int l = i;
for(int j = i + 1; j <= N ; ++j) {
if(fabs(a.f[j][i]) > fabs(a.f[l][i])) l = j;
}
if(fabs(a.f[l][i]) < 1e-8) {flag = 1;return b;}
if(i != l) {
for(int j = 1 ; j <= N ; ++j) {
swap(a.f[i][j],a.f[l][j]);
swap(b.f[i][j],b.f[l][j]);
}
}
db t = 1.0 / a.f[i][i];
for(int j = 1 ; j <= N ; ++j) {
a.f[i][j] *= t;
b.f[i][j] *= t;
}
for(int j = 1 ; j <= N ; ++j) {
if(i == j) continue;
db t = a.f[j][i];
for(int k = 1 ; k <= N ; ++k) {
a.f[j][k] -= t * a.f[i][k];
b.f[j][k] -= t * b.f[i][k];
}
}
}
return b;
}
}A,B,C;
bool match(int u) {
for(int i = 1 ; i <= N ; ++i) {
if(g[u][i]) {
if(!vis[i]) {
vis[i] = 1;
if(!matc[i] || match(matc[i])) {
matc[i] = u;matk[u] = i;
return true;
}
}
}
}
return false;
}
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) {
for(int j = 1 ; j <= N ; ++j) {
scanf("%lf",&A.f[i][j]);
}
}
for(int i = 1 ; i <= N ; ++i) {
for(int j = 1 ; j <= N ; ++j) {
scanf("%lf",&C.f[i][j]);
}
}
B = ~A;
if(flag) {
puts("NIE");return;
}
C = C * B;
for(int i = 1 ; i <= N ; ++i) {
for(int j = 1 ; j <= N ; ++j) {
if(fabs(C.f[i][j]) > 1e-8) {
g[j][i] = 1;
}
}
}
for(int i = 1 ; i <= N ; ++i) {
memset(vis,0,sizeof(vis));
if(!match(i)) {
puts("NIE");return;
}
}
puts("TAK");
for(int i = 1 ; i <= N ; ++i) {
for(int j = 1 ; j <= N ; ++j) {
if(!g[i][j]) continue;
if(matk[i] == j) break;
if(matc[j] < i) continue;
memset(vis,0,sizeof(vis));
for(int k = 1 ; k < i ; ++k) vis[matk[k]] = 1;
vis[j] = 1;
int t = matk[i];
matc[t] = 0;
if(match(matc[j])) {
matk[i] = j;matc[j] = i;
break;
}
else {
matc[t] = i;
}
}
}
for(int i = 1 ; i <= N ; ++i) {
out(matk[i]);enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}
【BZOJ】3168: [Heoi2013]钙铁锌硒维生素的更多相关文章
- BZOJ 3168: [Heoi2013]钙铁锌硒维生素 [线性基 Hungary 矩阵求逆]
3168: [Heoi2013]钙铁锌硒维生素 题意:给一个线性无关组A,再给一个B,要为A中每个向量在B中选一个可以代替的向量,替换后仍然线性无关.判断可行和求字典序最小的解 PoPoQQQ orz ...
- BZOJ 3168 Heoi2013 钙铁锌硒维生素 矩阵求逆+匈牙利算法
题目大意:给定一个n∗n的满秩矩阵A和一个n∗n的矩阵B.求一个字典序最小的1...n的排列a满足将随意一个Ai换成Bai后矩阵A仍然满秩 我们考虑建立一个二分图.假设Ai能换成Bj.就在i−> ...
- BZOJ 3168 [Heoi2013]钙铁锌硒维生素 ——矩阵乘法 矩阵求逆
考虑向量ai能否换成向量bj 首先ai都是线性无关的,然后可以a线性表出bj c1*a1+c2*a2+...=bj 然后移项,得 c1/ci*a1+...-1/ci*bj+...=ai 所以当ci不为 ...
- 洛谷 P4100 [HEOI2013]钙铁锌硒维生素 解题报告
P4100 [HEOI2013]钙铁锌硒维生素 题目描述 银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加 宇宙比赛的饮食. 众所周知,前往宇宙的某个星球,通常要花费好长好长的时间, ...
- 【BZOJ3168】[Heoi2013]钙铁锌硒维生素 高斯消元求矩阵的逆+匈牙利算法
[BZOJ3168][Heoi2013]钙铁锌硒维生素 Description 银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加宇宙比赛的饮食.众所周知,前往宇宙的某个星球,通常要花 ...
- BZOJ 3168 Luogu P4100 [HEOI2013]钙铁锌硒维生素 (矩阵求逆、二分图匹配)
线性代数+图论好题. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3168 (luogu) https://www.lu ...
- BZOJ3168. [HEOI2013]钙铁锌硒维生素(线性代数+二分图匹配)
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=3168 题解 首先,我们需要求出对于任意的 \(i, j(1 \leq i, j \leq ...
- BZOJ3168: [Heoi2013]钙铁锌硒维生素
设$A^TC=B^T$,这样$C_{ij}$表示$B_j$的线性表出需要$A_i$,那么$B_j$可以替换$A_i$,根据$C=(A^T)^{-1}B^T$求出$C$.要求字典序最小完美匹配,先求任意 ...
- bzoj 3165: [Heoi2013]Segment 动态凸壳
3165: [Heoi2013]Segment Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 202 Solved: 89[Submit][Stat ...
随机推荐
- 【题解】 bzoj4004: [JLOI2015]装备购买 (线性基)
bzoj4004,戳我戳我 Solution: 裸的线性基,这没啥好说的,我们说说有意思的地方(就是我老是wa的地方) Attention: 这题在\(luogu\),上貌似不卡精度,\(bzoj\) ...
- Spring Boot -Shiro配置多Realm
核心类简介 xxxToken:用户凭证 xxxFilter:生产token,设置登录成功,登录失败处理方法,判断是否登录连接等 xxxRealm:依据配置的支持Token来认证用户信息,授权用户权限 ...
- emWin 工程之汉字显示
@2018-7-10 工程加入字库后,液晶屏显示非法文字,无法正确显示设置的文字 解决办法 将显示汉字的文件 <MainTask.c> 修改为 UTF-8 格式后显示正常,修改为 ANS ...
- python 用Threading创建多线程
#-*-coding:utf-8-*- '''python标准库提供了两个多线程模块,分别为thread和threading, 其中thread模块是低级模块,threading是高级模块,对thre ...
- 在windows上部署使用Redis出现问题的解决方法
下载Redis 在Redis的官网下载页上有各种各样的版本,我这次是在windows上部署的,要去GitHub上下载.目前的是2.8.12版的,直接解压,在\bin\release 目录下有个压缩包, ...
- LeetCode 7最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...
- RabbitMQ集群和高可用配置
概述 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java.JMS.C.PHP.ActionScript.XMPP. ...
- node爬虫入门
爬虫其实就是模仿浏览器访问页面,然后把页面保存起来备用. 爬虫的方法,直接上代码: function getUrl(url,success,error){ let urlObj = urlParser ...
- TradingView学习记录
官网:https://cn.tradingview.com 申请图表库 用本地服务器打开 二:文件目录 三:基础概念 3.1 UDF:通用数据饲料(Universal Data Feed) ...
- SQL记录-PLSQL运算符
PL/SQL运算符 运算符是一个符号,告诉编译器执行特定的数学或逻辑操作. PL/SQL语言有丰富的内置运算符,运算符提供的以下几种类型: 算术运算符 关系运算符 比较运算符 逻辑运算符 字符串运算符 ...