不想學帶花樹,於是乎就學了一發高斯消元版的一般圖匹配……
這個東西的優點肯定是有的,最主要的是不用去學習帶花樹的那一套理論了,只需要會用高斯消元就行,代碼難度相比帶花樹來說小一些。當然缺點也有,最要命的就是常數太大,不卡一下常都過不了UOJ#79……
貼一份UOJ#79的板子,懶得解釋了,不要介意……
UPD:一開始貼的板子似乎有錯,重新貼一個應該沒錯的板子好了

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=505,p=1000000007; 6 void Gauss(int[][maxn],int[][maxn],int); 7 void eliminate(int,int); 8 int qpow(int,int); 9 int A[maxn][maxn],B[maxn][maxn],t[maxn][maxn],id[maxn],a[maxn]; 10 bool row[maxn]={false},col[maxn]={false}; 11 int n,m,girl[maxn]; 12 int main(){ 13 srand(23333333); 14 scanf("%d%d",&n,&m); 15 while(m--){ 16 int x,y; 17 scanf("%d%d",&x,&y); 18 A[x][y]=rand()%p; 19 A[y][x]=-A[x][y]; 20 } 21 for(int i=1;i<=n;i++)id[i]=i; 22 memcpy(t,A,sizeof(t)); 23 Gauss(A,NULL,n); 24 m=n; 25 n=0; 26 for(int i=1;i<=m;i++)if(A[id[i]][id[i]])a[++n]=i; 27 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)A[i][j]=t[a[i]][a[j]]; 28 Gauss(A,B,n); 29 for(int i=1;i<=n;i++)if(!girl[a[i]]) 30 for(int j=i+1;j<=n;j++)if(!girl[a[j]]&&t[a[i]][a[j]]&&B[j][i]){ 31 girl[a[i]]=a[j]; 32 girl[a[j]]=a[i]; 33 eliminate(i,j); 34 eliminate(j,i); 35 break; 36 } 37 printf("%d\n",n>>1); 38 for(int i=1;i<=m;i++)printf("%d ",girl[i]); 39 return 0; 40 } 41 void Gauss(int A[][maxn],int B[][maxn],int n){ 42 if(B){ 43 memset(B,0,sizeof(t)); 44 for(int i=1;i<=n;i++)B[i][i]=1; 45 } 46 for(int i=1;i<=n;i++){ 47 if(!A[i][i]){ 48 for(int j=i+1;j<=n;j++)if(A[j][i]){ 49 swap(id[i],id[j]); 50 for(int k=i;k<=n;k++)swap(A[i][k],A[j][k]); 51 if(B)for(int k=1;k<=n;k++)swap(B[i][k],B[j][k]); 52 break; 53 } 54 if(!A[i][i])continue; 55 } 56 int inv=qpow(A[i][i],p-2); 57 for(int j=1;j<=n;j++)if(i!=j&&A[j][i]){ 58 int t=(long long)A[j][i]*inv%p; 59 for(int k=i;k<=n;k++)if(A[i][k])A[j][k]=(A[j][k]-(long long)t*A[i][k])%p; 60 if(B)for(int k=1;k<=n;k++)if(B[i][k])B[j][k]=(B[j][k]-(long long)t*B[i][k])%p; 61 } 62 } 63 if(B)for(int i=1;i<=n;i++){ 64 int inv=qpow(A[i][i],p-2); 65 for(int j=1;j<=n;j++)if(B[i][j])B[i][j]=(long long)B[i][j]*inv%p; 66 } 67 } 68 void eliminate(int r,int c){ 69 row[r]=col[c]=true; 70 int inv=qpow(B[r][c],p-2); 71 for(int i=1;i<=n;i++)if(!row[i]&&B[i][c]){ 72 int t=(long long)B[i][c]*inv%p; 73 for(int j=1;j<=n;j++)if(!col[j]&&B[r][j])B[i][j]=(B[i][j]-(long long)t*B[r][j])%p; 74 } 75 } 76 int qpow(int a,int b){ 77 int ans=1; 78 for(;b;b>>=1,a=(long long)a*a%p)if(b&1)ans=(long long)ans*a%p; 79 return ans; 80 }
注意,直接寫的話會在第17個測試點TLE,這時就需要加上一些卡常技巧:在乘法之前判斷乘數是否為0,以及消元時乘法之后不要取模,減完之后再一起取模,可以減少一次取模。
目前為止只寫過板子(並且寫得也不熟……),其他題還沒做過,還是需要多加練習……