码迷,mamicode.com
首页 > 其他好文 > 详细

一般图匹配

时间:2017-07-12 21:25:59      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:维护   iostream   tin   using   cst   http   get   color   api   

tutte矩阵

技术分享

一般图的最大匹配数为tutte矩阵的秩(必为偶数)除2

求出最大匹配后加入(n-2*最大匹配数)个点与所有点连边,新图一定存在最大匹配

与新点匹配的点在原图中不与任何点匹配

求一张图的完美匹配时可尝试删除一条边,两个点看是否仍存在完美匹配

有结论两点i,j可能在最大匹配中当且仅当

A的逆矩阵[j][i]不为0且i,j有边相连

删除一条边时可以以第i行的第j列为主元,第j行的第i列为主元消元维护逆矩阵

复杂度O(n^3)常数巨大。

#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <cmath>
#define LL long long
using namespace std;

  const LL mo=1e9+7;
  LL sed=12939512;

  int n,m;
  int b[2001],fin[2001];
  int sid[124751][2],cnt,edge[2001][2001];
  LL ran(){
      sed*=21409124;sed+=1249134;sed^=1234904;sed%=mo;
      return(sed);
  }

  LL qpow(LL bas,int powe){
      LL ret=1;
      for (;powe;bas*=bas,bas%=mo){
        if (powe&1) ret*=bas,ret%=mo;
      powe>>=1;    
    }
    return(ret);
  }

  struct matrix{
    LL a[1201][1201],tmp[1201][1201];
    int n,m;
    
    int getrank(){
      for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) tmp[i][j]=a[i][j];
      for (int i=1;i<=n;i++){
          for (int j=i;j<=n;j++) if (a[j][i]) {swap(a[j],a[i]);break;}
          if (!a[i][i]) continue;
          LL inv=qpow(a[i][i],mo-2);
        for (int j=i+1;j<=n;j++){
          LL bas=a[j][i]*inv%mo;
          if (!bas) continue;
          for (int k=i;k<=n;k++)
            if (a[i][k])
              a[j][k]-=a[i][k]*bas%mo,a[j][k]%=mo,a[j][k]+=mo,a[j][k]%=mo;
          }    
      }
      LL ret=0;
      for (int i=1;i<=n;i++) if (a[i][i]) ret++;
      return(ret);
    }
    
    void getinv(){
      for (int i=1;i<=n;i++) a[i][n+i]=1;
      for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) a[i][j]=(a[i][j]%mo+mo)%mo;
      for (int i=1;i<=n;i++){
        int po;LL maxi=0;
        for (int j=i;j<=n;j++){
          if (abs(a[j][i])>maxi){
            maxi=abs(a[j][i]);po=j;
          }
        }
        for (int j=1;j<=2*n;j++){
          LL t=a[i][j];a[i][j]=a[po][j];a[po][j]=t;
        }
        if (abs(maxi)==0) continue;
        
        LL rev=qpow(a[i][i],mo-2);    
        for (int j=i+1;j<=n;j++){
          LL tim=a[j][i]*rev%mo;
          for (int k=i;k<=2*n;k++) a[j][k]-=a[i][k]*tim%mo,a[j][k]%=mo;
          }
        }
        
        for (int i=1;i<=n;i++) for (int j=1;j<=2*n;j++) a[i][j]=(a[i][j]%mo+mo)%mo;
        for (int i=n;i>=1;i--){
          for (int j=i+1;j<=n;j++){
            for (int k=n+1;k<=2*n;k++)
              a[i][k]-=a[i][j]*a[j][k]%mo,a[i][k]%=mo;
            a[i][j]=0;          
          }
          for (int j=n+1;j<=2*n;j++)
            a[i][j]*=qpow(a[i][i],mo-2),a[i][j]%=mo;
          a[i][i]=1;  
        }
        
        for (int i=1;i<=n;i++)
          for (int j=1;j<=n;j++)
            a[i][j]=(a[i][j+n]%mo+mo)%mo;
    }
    
    void elim(int x,int y){
      for (int i=1;i<=n;i++)
        if (!b[i]){
          LL bas=a[i][y]*qpow(a[x][y],mo-2)%mo;
          for (int j=1;j<=n;j++){
            a[i][j]-=a[x][j]*bas%mo;
            a[i][j]%=mo;a[i][j]+=mo;a[i][j]%=mo;
          }
        }
    }
  }a;

  int main(){      
      scanf("%d%d",&n,&m);
      a.n=a.m=n;
      for (int i=1;i<=m;i++){
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        sid[++cnt][0]=t1;sid[cnt][1]=t2;
      LL num=ran();
      a.a[min(t1,t2)][max(t1,t2)]=num;
      a.a[max(t1,t2)][min(t1,t2)]=mo-num;
    }
    int ans=a.getrank()/2;
    printf("%d\n",ans);
    
    int addin=n-ans*2;
    a.n=n+addin;a.m=n+addin;
    for (int i=1;i<=a.n;i++) for (int j=1;j<=a.m;j++) a.a[i][j]=0;
    for (int i=1;i<=cnt;i++){
      LL num=ran();
      a.a[min(sid[i][0],sid[i][1])][max(sid[i][0],sid[i][1])]=num;
      a.a[max(sid[i][0],sid[i][1])][min(sid[i][0],sid[i][1])]=-num;
      edge[min(sid[i][0],sid[i][1])][max(sid[i][0],sid[i][1])]=1;
      edge[max(sid[i][0],sid[i][1])][min(sid[i][0],sid[i][1])]=1;
    }
    for (int i=1;i<=addin;i++) 
      for (int j=1;j<=n;j++){
          LL num=ran();
          a.a[j][n+i]=num;
          a.a[n+i][j]=-num;
          edge[j][n+i]=edge[n+i][j]=1;
      }
    a.getinv();
    
    for (int i=1;i<=n;i++) if (!b[i]){
      for (int j=i+1;j<=n+addin;j++)
        if (edge[i][j]&&a.a[j][i]!=0&&!b[j]){
          fin[i]=j;fin[j]=i;
          b[i]=1;b[j]=1;
          a.elim(i,j);
          a.elim(j,i);
          break;
        }
    }
    for (int i=1;i<=n;i++) printf("%d ",(fin[i]<=n ? fin[i]:0));
  }

 

一般图匹配

标签:维护   iostream   tin   using   cst   http   get   color   api   

原文地址:http://www.cnblogs.com/zhujiangning/p/7157465.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!