二分图带权最大匹配(二分图最优匹配)

二分图带权最大匹配(二分图最优匹配)

KM算法在稠密图上效率高于费用流。局限性:只能在满足“带权最大匹配一定是完备匹配”的途中正确求解。

若相等子图中存在完备匹配,则这个完备匹配就是二分图的带权最大匹配。

KM算法 O(n^4)

1-N 和 0 -N 全局一致; u和v一致;

# include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int INF=0x7fffffff;
const int MAXN=550;
int N;
struct KM{
   vector<int> G[MAXN];
   int W[MAXN][MAXN];
   int Lx[MAXN],Ly[MAXN];
   int Left[MAXN];//右边的点匹配左边的哪一个
   int S[MAXN],T[MAXN];
   void init()
  {
       for(int i=1;i<=N;++i) G[i].clear();
       memset(W,0,sizeof(W));
  }
   void add(int u,int v,int w)
  {
       G[u].push_back(v);
       W[u][v]=w;
  }
   int M(int u)
  {
       S[u]=1;
       int len=G[u].size();
       for(int i=0;i<len;++i){
           int v=G[u][i];
           if(Lx[u]+Ly[v]==W[u][v]&&!T[v]){
               T[v]=1;
               if(Left[v]==-1||M(Left[v])){
                   Left[v]=u;
                   return 1;
              }
          }
      }
       return 0;
  }
   void update()
  {
       int a=INF;
       for(int u=1;u<=N;++u){
           if(S[u]){
               int len=G[u].size();
               for(int i=0;i<len;++i){
                   int v=G[u][i];
                   if(!T[v]) a=min(a,Lx[u]+Ly[v]-W[u][v]);
              }
          }
      }
       for(int i=1;i<=N;++i){
           if(S[i]) Lx[i]-=a;
           if(T[i]) Ly[i]+=a;
      }
  }
   void solve()
  {
       for(int i=1;i<=N;++i){
           Lx[i]=*max_element(W[i]+1,W[i]+N+1);
           Left[i]=-1;
           Ly[i]=0;
      }
       for(int u=1;u<=N;++u){
           for(;;){
               for(int i=1;i<=N;++i) S[i]=T[i]=0;
               if(M(u)) break;
               else{
                   update();
              }
          }
      }
  }
}kme;
int pri[MAXN][MAXN];
int main()
{
   while(~scanf("%d",&N)){
       kme.init();
       for(int i=1;i<=N;++i){
           for(int j=1;j<=N;++j){
               scanf("%d",&pri[i][j]);
               kme.add(i,j,pri[i][j]);
          }
      }
       kme.solve();
       LL ans=0;
       for(int i=1;i<=N;++i){
           ans+=1ll*pri[kme.Left[i]][i];
      }
       printf("%lld\n",ans);
  }
   return 0;
}

Ladies’ Choice 提交

# include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int INF=0x7fffffff;
const int MAXN=2e3+100;
int N;
struct KM{
   vector<int> G[MAXN];
   int W[MAXN][MAXN];
   int Lx[MAXN],Ly[MAXN];
   int Left[MAXN];//右边的点匹配左边的哪一个
   int S[MAXN],T[MAXN];
   void init()
  {
       for(int i=1;i<=N;++i) G[i].clear();
       memset(W,0,sizeof(W));
  }
   void add(int u,int v,int w)
  {
       G[u].push_back(v);
       W[u][v]=w;
  }
   bool M(int u)
  {
       S[u]=1;
       int len=G[u].size();
       for(int i=0;i<len;++i){
           int v=G[u][i];
           if(Lx[u]+Ly[v]==W[u][v]&&!T[v]){
               T[v]=1;
               if(Left[v]==-1||M(Left[v])){
                   Left[v]=u;
                   return true;
              }
          }
      }
       return false;
  }
   void update()
  {
       int a=INF;
       for(int u=1;u<=N;++u){
           if(S[u]){
               int len=G[u].size();
               for(int i=0;i<len;++i){
                   int v=G[u][i];
                   if(!T[v]){
                       a=min(a,Lx[u]+Ly[v]-W[u][v]);
                  }
              }
          }
      }
       for(int i=1;i<=N;++i){
           if(S[i]) Lx[i]-=a;
           if(T[i]) Ly[i]+=a;
      }
  }
   void solve()
  {
       for(int i=1;i<=N;++i){
           Lx[i]=*max_element(W[i]+1,W[i]+N+1);
           Left[i]=-1;
           Ly[i]=0;
      }
       for(int u=1;u<=N;++u){
           while(1){
               for(int i=1;i<=N;++i) S[i]=T[i]=0;
               if(M(u)){
                   break;
              }
               else{
                   update();
              }
          }
      }
  }
}kme;
int main()
{
   int T; scanf("%d",&T);
   while(T--){
       scanf("%d",&N);
       kme.init();
       int id,a;
       for(int i=1;i<=N;++i){
           for(int j=N;j>=1;j--){
               scanf("%d",&a);
               kme.W[i][a]=j*i;
               kme.add(i,a,j*i);
          }
      }
       for(int i=1;i<=N;++i){
           for(int j=N;j>=1;j--){
               scanf("%d",&a);
               //kme.W[a][i]=j;
               //kme.add(a,i,j);
          }
      }
       kme.solve();
       for(int i=1;i<=N;++i){
           for(int j=1;j<=N;++j){
               if(kme.Left[j]==i){
                   printf("%d\n",j);
              }
          }
      }
  }

   return 0;
}
/*
1
5
1 2 3 5 4
5 2 4 3 1
3 5 1 2 4
3 4 2 1 5
4 5 1 2 3
2 5 4 1 3
3 2 4 1 5
1 2 4 3 5
4 1 2 5 3
5 3 2 4 1
*/



posted @   fengzlj  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示