Input
Output
Sample Input
1 0 0
0 1 0
0 0 1
2 3 0
0 7 8
0 0 9
Sample Output
1
2
3
这道题是在找二分图相关的题时候找到的,看了以后发现建图才是关键。题意一开始并没有理解清楚,一定要仔细读题,一定要仔细读题,一定要仔细读题。
题目一开始给了两个矩阵A,B,其实就是看B的某一行能代替A的哪些行,通过这个建图,之后直接跑最大匹配验证一下就可以了。这样我们把矩阵A看作是n个向量,每一行都代表一个n维向量,以他们建立n维坐标系,因为题目保证一开始能搭配出任何营养需求,那就是说这个n维空间每个地方都可以被这些向量所表示出来,而且这样的话矩阵A就显然是一个满秩矩阵了,并且B替换A的一行时,还要保证换完以后A还是一个满秩矩阵。
之后我们设出一个系数矩阵C,使得C * A = B,我们现在想C的实际意义,AB中每个机器人对应着一个行向量,所以行向量对应 就需要是CA=B而不是AC=B,如果说C的某一个位置是0 (假设是第i行 第j列),那么也就意味着并不用A中的第j行来表示B中的第i行,这两个行向量是无关的。或者可以理解成,在这个n维空间里,这两个向量是垂直的,也就是我们不能用矩阵B的第i行来代替矩阵A的第j行。
这样只需要求出C就可以了,只要C(i,j) != 0那么B的第i行就能够代替A的第j行 。由于题目保证A是满秩的,所以可以直接求A的逆矩阵A-1,可得C=B A-1依此建图即可,不过题目要求是A的代替方案字典序最小,所以实际建图的邻接矩阵是C的转置矩阵。
跑二分图匹配由于要求字典序最小,所以跑完美匹配,如果可行,再去由小到大贪心的去换边,也就是再跑一次匈牙利算法。(有人说实际上数据并没有保证A是满秩的,所以高斯消元的时候判断一下。)
下面是代码:(比较丑)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 using namespace std; 7 double a[310][310],b[310][310],c[310][310],ni[310][310]; 8 int n,mat[310],ans[310]; 9 bool vis[310],nxt[310][310]; 10 bool ling(double x){ 11 if(fabs(x)<1e-8) return true; 12 return false; 13 } 14 bool gauss(){ 15 int i,j,k; 16 double t; 17 for(i=1;i<=n;i++){ 18 for(j=i;j<=n;j++) if(ling(a[j][i])==false) break; 19 if(i!=j) for(k=1;k<=n;k++) swap(a[i][k],a[j][k]),swap(ni[i][k],ni[j][k]); 20 if(ling(a[i][i])==true) return false; 21 t=1/a[i][i]; 22 for(k=1;k<=n;k++) a[i][k]*=t,ni[i][k]*=t; 23 for(j=1;j<=n;j++){ 24 if(i==j) continue; 25 t=a[j][i]; 26 for(k=1;k<=n;k++){ 27 a[j][k]-=a[i][k]*t; 28 ni[j][k]-=ni[i][k]*t; 29 } 30 } 31 } 32 return true; 33 } 34 void jucheng(){ 35 int i,j,k; 36 for(i=1;i<=n;i++){ 37 for(j=1;j<=n;j++){ 38 for(k=1;k<=n;k++){ 39 c[i][j]+=b[i][k]*ni[k][j]; 40 } 41 } 42 } 43 for(i=1;i<=n;i++){ 44 for(j=1;j<=n;j++){ 45 if(ling(c[i][j])==false) nxt[j][i]=true; 46 else nxt[j][i]=false; 47 } 48 } 49 } 50 bool dfs1(int pos){ 51 for(int i=1;i<=n;i++){ 52 if(nxt[pos][i]==false||vis[i]==false) continue; 53 vis[i]=false; 54 if(mat[i]==0||dfs1(mat[i])==true){ 55 mat[i]=pos; 56 ans[pos]=i; 57 return true; 58 } 59 } 60 return false; 61 } 62 bool dfs2(int pos,int frm){ 63 for(int i=1;i<=n;i++){ 64 if(nxt[pos][i]==false||vis[i]==false) continue; 65 vis[i]=false; 66 if(mat[i]==frm||(mat[i]>frm&&dfs2(mat[i],frm)==true)){ 67 mat[i]=pos; 68 ans[pos]=i; 69 return true; 70 } 71 } 72 return false; 73 } 74 int main() 75 { 76 int i,j; 77 scanf("%d",&n); 78 for(i=1;i<=n;i++){ 79 for(j=1;j<=n;j++){ 80 scanf("%lf",&a[i][j]); 81 } 82 } 83 for(i=1;i<=n;i++){ 84 for(j=1;j<=n;j++){ 85 scanf("%lf",&b[i][j]); 86 } 87 } 88 memset(c,0,sizeof(c)); 89 memset(ni,0,sizeof(ni)); 90 memset(mat,0,sizeof(mat)); 91 for(i=1;i<=n;i++) ni[i][i]=1; 92 if(gauss()==false){ 93 printf("NIE\n"); 94 return 0; 95 } 96 jucheng(); 97 for(i=1;i<=n;i++){ 98 memset(vis,true,sizeof(vis)); 99 if(dfs1(i)==false){ 100 printf("NIE\n"); 101 return 0; 102 } 103 } 104 for(i=1;i<=n;i++){ 105 memset(vis,true,sizeof(vis)); 106 dfs2(i,i); 107 } 108 printf("TAK\n"); 109 for(i=1;i<=n;i++) printf("%d\n",ans[i]); 110 }