返回顶部

P6577 【模板】二分图最大权完美匹配 (KM)

$\quad $ 初看就发现不对劲了,模板紫题,一看就不简单,就交了个裸\(KM\),哎,果然\(T\)了。

$\quad $ 然后就是大力卡常(当然\(O(n^4)\)的复杂度不是卡常能解决的)。遂看题解,发现一个据说\(O(n^3)\)的复杂度的\(KM\),也是非常抽象。
具体解释详见 https://www.luogu.com.cn/article/ip2m1gut

$\quad $ 当我还在研究题解的时候\(luobutianle\)直接就是溜过来跟我说倒着遍历可以起飞。我当时就是蒙,他就直接让我试了试,也是确实起飞了。

$\quad $ 大抵是造数据的人想卡\(KM\),认为人们都是正着遍历,就正着卡了。

献上我的大力卡常代码(当然过了)

点击查看代码
  #include<bits/stdc++.h>
  using namespace std;
  #define int long long
  const int N=550,M=250500;
  int match[N],slack[N],a[N],b[N],w[N][N],n,m,vis[N],rnd;
  int r(){
  	int ans=0;bool f=0;char ch=getchar();
  	while(ch<'0' || ch>'9'){if(ch=='-')f=1;ch=getchar();}
  	while(ch>='0' && ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
  	return f?~ans+1:ans;
  }
  bool dfs(int x){
      for(int i=1;i<=n;i=-~i){
          if(vis[i]^rnd){
              if(!((a[x]+b[i])^w[x][i])){
                  vis[i]=rnd;
                  if(!match[i]||dfs(match[i])){
                      match[i]=x;
                      return true;
                  }
              }else slack[i]=min(slack[i],a[x]+b[i]-w[x][i]);
          }
      }
      return false;
  }
  void write(long long n){
  	if(n>9)write(n/10);
  	putchar(n%10+'0');
  }
  signed main(){
      freopen("1.in","r",stdin);
      n=r(),m=r();
      for(int i=0;i<=n;i=-~i){
          for(int j=0;j<=n;j=-~j){
              w[i][j]=-9999999999;
          }
      }
      for(int i=1;i<=m;i=-~i)
          w[r()][r()]=r();
      for(int i=0;i<=n;i=-~i)a[i]=-99999999999;
      for(int i=1;i<=n;i=-~i){
          for(int j=1;j<=n;j=-~j){
              a[i]=max(a[i],w[i][j]);
          }
      }
      for(int i=0;i<=n;i=-~i)slack[i]=99999999999;
      for(int i=n;i>=1;i--){
          while(1){
              rnd++;
              if(dfs(i))break;
              int d=1e18;
              for(int j=1;j<=n;j++)if(vis[j]^rnd)d=min(d,slack[j]),slack[j]=99999999999;
              for(int j=1;j<=n;j++)if(vis[j]==rnd)b[j]+=d,a[match[j]]-=d;
              a[i]-=d;
          }
      }
      int ans=0;
      for(int i=1;i<=n;i=-~i)
          ans+=a[i]+b[i];
      ans<0?putchar('-'),ans=-ans:0;
      write(ans);
      putchar('\n');
      for(int i=1;i<=n;i=-~i)write(match[i]),putchar(' ');
      return 0;
  }

还有优化代码:

点击查看代码
  #include<bits/stdc++.h>
  using namespace std;
  #define int long long
  const int N=550,M=250500;
  int match[N],slack[N],a[N],b[N];
  int vis[N],rnd,pre[N];
  bool vx[N],vy[N];
  int matchy[N],matchx[N];
  int w[N][N],n,m;
  queue<int>q;
  long long r(){
  	long long ans=0;bool f=0;char ch=getchar();
  	while(ch<'0' || ch>'9'){if(ch=='-')f=1;ch=getchar();}
  	while(ch>='0' && ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
  	return f?~ans+1:ans;
  }
  void fl(int x){
      int t;
      while(x){
          t=matchx[pre[x]];
          matchx[pre[x]]=x;
          matchy[x]=pre[x];
          x=t;
      }
      return;
  }
  void dfs(int l){
      memset(vx,0,sizeof vx);
      memset(vy,0,sizeof vy);
      memset(slack,0x7f,sizeof slack);
      while(q.size())q.pop();
      q.push(l);
      while(1){
          while(q.size()){
              int x=q.front();q.pop();
              vx[x]=1;
              for(int i=1;i<=n;i++){
                  if(vy[i]!=1){
                      if(a[x]+b[i]-w[x][i]<slack[i]){
                          slack[i]=a[x]+b[i]-w[x][i];
                          pre[i]=x;
                          if(!slack[i]){
                              vy[i]=1;
                              if(!matchy[i]){
                                  fl(i);
                                  return;
                              }else q.push(matchy[i]);
                          }
                      }
                  }
              }
          }
          int d=1e18;
          for(int i=1;i<=n;i++)if(vy[i]!=1)d=min(d,slack[i]);
          for(int i=1;i<=n;i++){
              if(vx[i]==1)a[i]-=d;
              if(vy[i]==1)b[i]+=d;
              else slack[i]-=d;
          }
          for(int i=1;i<=n;i++){
              if(vy[i]!=1){
                  if(!slack[i]){
                      vy[i]=1;
                      if(!matchy[i]){
                          fl(i);
                          return;
                      }else q.push(matchy[i]);
                  }
              }
          } 
      }
  }
  void wr(int x){
      if(x>9)wr(x/10);
      putchar(x%10+'0');
  }
  signed main(){
      n=r(),m=r();
      memset(w,0xcf,sizeof w);
      for(int i=1;i<=m;i++){
          w[r()][r()]=r();
      }
      memset(a,0xcf,sizeof a);
      for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
              a[i]=max(a[i],w[i][j]);
      for(int i=1;i<=n;i++)dfs(i);
      int ans=0;
      for(int i=1;i<=n;i++)ans+=a[i]+b[i];
      ans<0?putchar('-'),ans=-ans:0;
      wr(ans);putchar('\n');
      for(int i=1;i<=n;i++)wr(matchy[i]),putchar(' ');
      return 0;
  }
posted @ 2024-05-14 11:59  无敌の暗黑魔王  阅读(18)  评论(0编辑  收藏  举报