UOJ#80 二分图最大权匹配 [模板题]

Posted SilverNebula

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOJ#80 二分图最大权匹配 [模板题]相关的知识,希望对你有一定的参考价值。

从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生。编号分别为 1,,nl1,…,nl 和 1,,nr1,…,nr。

有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为配偶,且结为配偶后幸福程度为 ww。

请问这个班级里幸福程度之和最大是多少?

输入格式

第一行三个正整数,nl,nr,mnl,nr,m。

接下来 mm 行,每行三个整数 v,u,wv,u,w 表示第 vv 个男生和第 uu 个女生愿意结为配偶,且幸福程度为 ww。保证 1vnl1≤v≤nl,1unr1≤u≤nr,保证同一对 v,uv,u 不会出现两次。

输出格式

第一行一个整数,表示幸福程度之和的最大值。

接下来一行 nlnl 个整数,描述一组最优方案。第 vv 个整数表示 vv 号男生的配偶的编号。如果 vv 号男生没配偶请输出 00。

样例一

input

2 2 3
1 1 100
1 2 1
2 1 1

output

100
1 0

限制与约定

1nl,nr4001≤nl,nr≤400,1m1600001≤m≤160000,1w1091≤w≤109。

时间限制1s1s

空间限制256MB

 

二分图最大权匹配模板题 KM算法

KM算法略神奇的样子……

http://www.cnblogs.com/wenruo/p/5264235.html

↑感觉这里讲得挺清晰

 

KM算法求的是最大权完备匹配,为了解决两边点数不同的情况,需要虚拟一些点使得两边点数相等

 

↑但是这种DFS写法被无情卡掉

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 #define LL long long
  9 using namespace std;
 10 const LL INF=1LL<<62;
 11 const int mxn=411;
 12 int read(){
 13     int x=0,f=1;char ch=getchar();
 14     while(ch<\'0\' || ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();}
 15     while(ch>=\'0\' && ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();}
 16     return x*f;
 17 }
 18 void write(LL x){
 19     if(x>9)write(x/10);
 20     putchar(x%10+\'0\');
 21     return;
 22 }
 23 inline LL mini(LL a,LL b){return a<b?a:b;}
 24 inline LL maxi(LL a,LL b){return a>b?a:b;}
 25 int nL,nR,bl,br,m;
 26 int visL[mxn],visR[mxn];
 27 LL exL[mxn],exR[mxn];
 28 int link[mxn];
 29 LL slack[mxn];
 30 int mp[mxn][mxn];
 31 LL ans=0;
 32 int a[mxn];
 33 int dtime=0;
 34 bool DFS(int u){
 35     visL[u]=dtime;
 36     for(int i=1;i<=nR;i++){
 37         if(visR[i]==dtime)continue;
 38         LL d=exL[u]+exR[i]-mp[u][i];
 39         if(!d){
 40             visR[i]=dtime;
 41             if(!link[i] || DFS(link[i])){
 42                 link[i]=u;
 43                 return 1;
 44             }
 45         }
 46         else slack[i]=min(slack[i],d);
 47     }
 48     return 0;
 49 }
 50 void KM(){
 51 //    memset(link,0,sizeof link);
 52 //    memset(exR,0,sizeof exR);
 53     for(int i=1;i<=nL;i++){
 54         exL[i]=0;
 55         for(int j=1;j<=nR;j++){
 56             exL[i]=maxi(exL[i],mp[i][j]);
 57         }
 58     }
 59     for(int i=1;i<=nL;i++){
 60 //        memset(slack,0x3f,sizeof slack);
 61         for(int j=1;j<=nR;j++)slack[j]=INF;
 62         while(1){//直到匹配成功为止 
 63             dtime++;
 64 //            memset(visL,0,sizeof visL);
 65 //            memset(visR,0,sizeof visR);
 66             if(DFS(i))break;
 67             LL d=INF;
 68             for(int j=1;j<=nR;j++){
 69                 if(visR[j]!=dtime)d=mini(d,slack[j]);
 70             }
 71             for(int j=1;j<=nL;j++){
 72                 if(visL[j]==dtime)exL[j]-=d;
 73                 if(visR[j]==dtime)exR[j]+=d;
 74                 else slack[j]-=d;
 75             }
 76         }
 77     }
 78     ans=0;
 79     nL=bl;nR=br;
 80     for(int i=1;i<=nR;i++){
 81         if(mp[link[i]][i]){
 82             a[link[i]]=i;
 83             ans+=mp[link[i]][i];
 84         }
 85     }
 86     printf("%lld\\n",ans);
 87     for(int i=1;i<=nL;i++){
 88         write(a[i]);
 89         putchar(\' \');
 90     }
 91     printf("\\n");
 92     return;
 93 }
 94 int main(){
 95     int i,j;
 96     nL=read();
 97     nR=read();
 98     bl=nL;br=nR;
 99     nL=max(nL,nR);
100     nR=nL;
101     m=read();
102     int u,v,w;
103     for(i=1;i<=m;i++){
104         u=read();v=read();w=read();
105         mp[u][v]=w;
106     }
107     KM();
108     return 0;
109 }
DFS TLE

 

于是在status里抄了个BFS的写法。

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 #define LL long long
  9 using namespace std;
 10 const int INF=0x3f3f3f3f;
 11 const int mxn=411;
 12 int read(){
 13     int x=0,f=1;char ch=getchar();
 14     while(ch<\'0\' || ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();}
 15     while(ch>=\'0\' && ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();}
 16     return x*f;
 17 }
 18 void write(LL x){
 19     if(x>9)write(x/10);
 20     putchar(x%10+\'0\');
 21     return;
 22 }
 23 inline int mini(int a,int b){return a<b?a:b;}
 24 inline int maxi(int a,int b){return a>b?a:b;}
 25 int nL,nR,bl,br,m;
 26 int visL[mxn],visR[mxn];
 27 int exL[mxn],exR[mxn];
 28 int link[mxn],pre[mxn],lx[mxn];
 29 int slack[mxn];
 30 int mp[mxn][mxn];
 31 //
 32 LL ans=0;
 33 int a[mxn];
 34 int dtime=0;
 35 int q[mxn<<1],hd,tl;
 36 void Aug(int rt){
 37     if(!rt)return;
 38     link[rt]=pre[rt];
 39     Aug(lx[pre[rt]]);
 40     lx[pre[rt]]=rt;
 41     return;
 42 }
 43 void BFS(int S){
 44     int i,j,tmp;++dtime;
 45     memset(slack,0x3f,sizeof slack);
 46     hd=tl=1;q[tl]=S;
 47     while(1){
 48         while(hd<=tl){
 49             int u=q[hd];++hd;
 50             visL[u]=dtime;
 51             for(int i=1;i<=nR;i++){
 52                 if(visR[i]^dtime){
 53                     tmp=exL[u]+exR[i]-mp[u][i];
 54                     if(!tmp){
 55                         visR[i]=dtime;pre[i]=u;
 56                         if(!link[i]){
 57                             Aug(i);
 58                             return;
 59                         }
 60                         q[++tl]=link[i];
 61                         //
 62                     }
 63                     else if(tmp<slack[i])slack[i]=tmp,pre[i]=u;
 64                 }
 65             }
 66         }
 67         tmp=INF;
 68         for(i=1;i<=nR;i++)if(visR[i]^dtime)tmp=mini(tmp,slack[i]);
 69         for(i=1;i<=nL;i++){
 70             if(visL[i]==dtime)exL[i]-=tmp;
 71             if(visR[i]==dtime)exR[i]+=tmp;
 72             else slack[i]-=tmp;
 73         }
 74         for(i=1;i<=nR;i++){
 75             if(visR[i]^dtime && !slack[i]){
 76                 visR[i]=dtime;
 77                 if(!link[i]){
 78 //                    link[i]=pre[i];
 79                     Aug(i);
 80                     return;
 81                 }
 82                 q[++tl]=link[i];
 83             }
 84         }
 85     }
 86     return;
 87 }
 88 void KM(){
 89     for(int i=1;i<=nL;i++){
 90         exL[i]=0;
 91         for(int j=1;j<=nR;j++)
 92             exL[i]=max(exL[i],mp[i][j]);
 93     }
 94     for(int i=1;i<=nL;i++) BFS(i);
 95     ans=0;
 96     nL=bl;nR=br;
 97     for(int i=1;i<=nR;i++){
 98         if(mp[link[i]][i]){
 99             a[link[i]]=i;
100             ans+=mp[link[i]][i];
101         }
102     }
103     printf("%lld\\n",ans);
104     for(int i=1;i<=nL;i++){
105         write(a[i]);
106         putchar(\' \');
107     }
108     printf("\\n");
109     return;
110 }
111 int main(){
112     int i,j;
113     nL=read();
114     nR=read();
115     bl=nL;br=nR;
116     nL=max(nL,nR);
117     nR=nL;
118     m=read();
119     int u,v,w;
120     for(i=1;i<=m;i++){
121         u=read();v=read();w=read();
122         mp[u][v]=w;
123     }
124     KM();
125     return 0;
126 }

 

以上是关于UOJ#80 二分图最大权匹配 [模板题]的主要内容,如果未能解决你的问题,请参考以下文章

uoj#80 二分图最大权匹配

UOJ 80 二分图最大权匹配

UOJ #80. 二分图最大权匹配

[kuangbin带你飞]专题十 匹配问题 一般图匹配

[kuangbin带你飞]专题十 匹配问题 二分图最大权匹配

二分图最大权完美匹配KM算法模板