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 }

 

posted @ 2019-03-05 14:10  Ressed  阅读(193)  评论(0编辑  收藏  举报