bzoj3168 钙铁锌硒维生素 (矩阵求逆+二分图最小字典序匹配)
设第一套为A,第二套为B
先对于每个B[i]判断他能否替代A[j],即B[i]与其他的A线性无关
设$B[i]=\sum\limits_{k}{c[k]*A[k]}$,那么只要看c[j]是否等于零即可,如果c[j]=0,就意味着可以用A[j]以外的线性表达出B[i],所以不能B[i]替换A[j],否则可以
于是高斯消元求出c矩阵,问题就转化成了求二分图的最小字典序匹配
先跑一遍匈牙利判下是否无解,然后以它为基准解再贪心地求一遍答案
具体地说,你做到第i个的时候,前i-1都要固定住,其他的和普通匈牙利是一样的
1 #include<bits/stdc++.h> 2 #include<tr1/unordered_map> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 #define MP make_pair 5 using namespace std; 6 typedef long long ll; 7 typedef unsigned long long ull; 8 typedef pair<int,int> pa; 9 typedef long double ld; 10 const int maxn=303,P=998244353; 11 12 inline ll rd(){ 13 ll x=0;char c=getchar();int neg=1; 14 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 15 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 16 return x*neg; 17 } 18 19 int N; 20 int a[maxn][maxn*2],b[maxn][maxn],c[maxn][maxn]; 21 bool can[maxn][maxn]; 22 23 inline int fpow(int x,int y){ 24 int re=1; 25 while(y){ 26 if(y&1) re=1ll*x*re%P; 27 x=1ll*x*x%P,y>>=1; 28 }return re; 29 } 30 31 inline void getinv(){ 32 for(int i=1;i<=N;i++){ 33 a[i][i+N]=1; 34 } 35 for(int i=1;i<=N;i++){ 36 int mi=i; 37 for(int j=i+1;j<=N;j++) if(a[j][i]) mi=j; 38 swap(a[mi],a[i]); 39 int iv=fpow(a[i][i],P-2); 40 for(int j=N*2;j>=i;j--) a[i][j]=1ll*a[i][j]*iv%P; 41 for(int j=i+1;j<=N;j++){ 42 for(int k=N*2;k>=i;k--) a[j][k]=(a[j][k]-1ll*a[i][k]*a[j][i])%P; 43 } 44 } 45 for(int i=N;i;i--){ 46 for(int j=i-1;j;j--){ 47 for(int k=N+1;k<=N*2;k++) a[j][k]=(a[j][k]-1ll*a[j][i]*a[i][k])%P; 48 } 49 } 50 for(int i=1;i<=N;i++){ 51 for(int j=1;j<=N;j++) a[i][j]=a[i][j+N]; 52 } 53 } 54 55 int bel[maxn],to[maxn];bool flag[maxn]; 56 57 bool dfs(int x){ 58 for(int i=1;i<=N;i++){ 59 if(!can[x][i]||flag[i]) continue; 60 flag[i]=1; 61 if(!bel[i]||dfs(bel[i])){bel[i]=x,to[x]=i;return 1;} 62 }return 0; 63 } 64 bool dfs2(int x,int y){ 65 for(int i=1;i<=N;i++){ 66 if(!can[x][i]||flag[i]) continue; 67 flag[i]=1; 68 if(bel[i]==y||(bel[i]>y&&dfs2(bel[i],y))){to[x]=i,bel[i]=x;return 1;} 69 }return 0; 70 } 71 72 int main(){ 73 //freopen("","r",stdin); 74 N=rd(); 75 for(int i=1;i<=N;i++){ 76 for(int j=1;j<=N;j++) a[i][j]=rd(); 77 } 78 for(int i=1;i<=N;i++){ 79 for(int j=1;j<=N;j++) b[i][j]=rd(); 80 } 81 getinv(); 82 for(int i=1;i<=N;i++){ 83 for(int j=1;j<=N;j++){ 84 for(int k=1;k<=N;k++){ 85 c[i][j]=(c[i][j]+1ll*b[i][k]*a[k][j])%P; 86 } 87 } 88 } 89 for(int i=1;i<=N;i++){ 90 for(int j=1;j<=N;j++){ 91 if(c[i][j]) can[j][i]=1; 92 } 93 }/* 94 for(int i=rd();i;i--){ 95 int a=rd(),b=rd(); 96 can[a][b]=1; 97 }*/ 98 bool bl=1; 99 for(int i=1;i<=N;i++){ 100 CLR(flag,0); 101 if(!dfs(i)){bl=0;break;} 102 } 103 if(!bl) printf("NIE\n"); 104 else{ 105 printf("TAK\n"); 106 for(int i=1;i<=N;i++){ 107 CLR(flag,0); 108 dfs2(i,i); 109 } 110 for(int i=1;i<=N;i++){ 111 printf("%d\n",to[i]); 112 } 113 } 114 return 0; 115 }