zoukankan      html  css  js  c++  java
  • 基于线性代数的一般图匹配

    不想学带花树,于是乎就学了一发高斯消元版的一般图匹配……

    这个东西的优点肯定是有的,最主要的是不用去学习带花树的那一套理论了,只需要会用高斯消元就行,代码难度相比带花树来说小一些。当然缺点也有,最要命的就是常数太大,不卡一下常都过不了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>>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 }
    View Code

    注意,直接写的话会在第17个测试点TLE,这时就需要加上一些卡常技巧:在乘法之前判断乘数是否为0,以及消元时乘法之后不要取模,减完之后再一起取模,可以减少一次取模。

    目前为止只写过板子(并且写得也不熟……),其他题还没做过,还是需要多加练习……

  • 相关阅读:
    js 屏蔽 键盘 按键
    什么情况下HttpContext.Current.Request.UrlReferrer为空
    vm下linux 按钮 vmware tools
    Table td中 div 不能100%的原因
    行转列
    office 2010 ;密钥
    HTTP 错误 500.21
    [Servlet3.0新特性]Servlet异步处理
    [Servlet3.0新特性]Serlvet文件上传
    [Servlet3.0新特性]注解替代配置文件
  • 原文地址:https://www.cnblogs.com/hzoier/p/6904943.html
Copyright © 2011-2022 走看看