zoukankan      html  css  js  c++  java
  • 一般图匹配

    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
    ",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));
      }

     -------------------------------

    以上方法可以解决必选点等问题。若只需求最大匹配,可发现最大匹配的点为tutte矩阵中最大线性无关组所对应的点。求最大匹配即可。

    在求逆和消元中进行一定的常数优化。

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #define LL long long
    using namespace std;
    
      const LL mo=1e9+7;
      LL sed=12939512;
    
      struct linknode{
          int pre,next;
      }row[2001],col[2001];
    
      int n,m;
      int b[2001],fin[2001];
      int sid[124751][2],cnt,edge[2001][2001],lis[2001],inlis[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++){
              if (!a[j][i]) continue;
              LL tim=a[j][i]*rev%mo;
              for (int k=i;k<=2*n;k++) if (a[i][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++) if (a[i][j]){
                for (int k=n+1;k<=2*n;k++) if (a[j][k])
                  a[i][k]-=a[i][j]*a[j][k]%mo,a[i][k]%=mo;
                a[i][j]=0;          
              }
              LL rev=qpow(a[i][i],mo-2);
              for (int j=n+1;j<=2*n;j++)
                if (a[i][j])
                  a[i][j]*=rev,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=0;i<=n;i=row[i].next)
            if (!b[i]){
              LL bas=a[i][y]*qpow(a[x][y],mo-2)%mo;
              for (int j=col[0].next;j<=n;j=col[j].next){
                a[i][j]-=a[x][j]*bas%mo;
                a[i][j]%=mo;a[i][j]+=mo;a[i][j]%=mo;
              }
            }
        }
      }a;
    
      void del(int po){
          b[po]=1;
          row[row[po].pre].next=row[po].next;
          row[row[po].next].pre=row[po].pre;
          col[col[po].pre].next=col[po].next;
          col[col[po].next].pre=col[po].pre;
      }
    
      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
    ",ans);
        
        m=0;
        for (int i=1;i<=n;i++) if (a.a[i][i]) lis[++m]=i,inlis[i]=m;
        for (int i=1;i<=m;i++){
          row[i].pre=i-1;row[i].next=i+1;
          col[i].pre=i-1;col[i].next=i+1;
        }
        row[0].next=col[0].next=1;
        for (int i=1;i<=a.n;i++) for (int j=1;j<=a.m;j++) a.a[i][j]=0;
        a.n=m;a.m=m;
        for (int i=1;i<=cnt;i++) if (inlis[sid[i][0]]&&inlis[sid[i][1]]){
          LL num=ran(),u=inlis[sid[i][0]],v=inlis[sid[i][1]];
          if (u>v) swap(u,v);
          a.a[u][v]=num;
          a.a[v][u]=-num;
          edge[u][v]=1;edge[v][u]=1;
        }
        a.getinv();
        
        for (int i=1;i<=m;i++) if (!b[i]){
          for (int j=i+1;j<=m;j++)
            if (edge[i][j]&&a.a[j][i]!=0&&!b[j]){
              fin[lis[i]]=lis[j];fin[lis[j]]=lis[i];
              del(i);del(j);
              a.elim(i,j);
              a.elim(j,i);
              break;
            }
        }
        for (int i=1;i<=n;i++) printf("%d ",fin[i]);
      }
  • 相关阅读:
    如果你也时常想要上进,我们可以相互鼓励,相互促进
    (转)Math.round(11.5)等于多少?Math.round(-11.5)等于多少?
    乐观锁和悲观锁(Version:0.1)
    redis数据丢失及解决【转】
    Spring的IOC原理[通俗解释一下]
    Java中Error与Exception的区别
    WebService
    JDBC详解
    Cookie与Session
    java的pojo规范
  • 原文地址:https://www.cnblogs.com/zhujiangning/p/7157465.html
Copyright © 2011-2022 走看看