二分图最大权匹配 费用流&KM

时间:2021-10-24 06:08:53

费用流 建图时额外添加一个点A(左->A:(1,0) A->T:(inf,0))来保证满流 边少点多较快 边多的情况下表现很差

二分图最大权匹配 费用流&KM二分图最大权匹配 费用流&KM
 1 #include<cstdio> 
 2 #include<cstring>
 3 #include<cmath>
 4 #include<ctime>
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<set>
 9 #define inf (1ll<<(61ll))
10 #define l(a) ((a)<<1)
11 #define r(a) ((a)<<1|1)
12 #define b(a) (1<<(a))
13 #define rep(i,a,b) for(int i=a;i<=(b);i++)
14 #define clr(a) memset(a,0,sizeof(a))
15 typedef long long ll;
16 using namespace std;
17 int readint(){
18     int t=0,f=1;char c=getchar();
19     while(!isdigit(c)){
20         if(c=='-') f=-1;
21         c=getchar();
22     }
23     while(isdigit(c)){
24         t=(t<<3)+(t<<1)+c-'0';
25         c=getchar();
26     }
27     return t*f;
28 }
29 const int maxn=1009,maxe=400009;
30 int n,m,en,S,A,T;
31 ll d[maxn];
32 ll ans;
33 struct edge{
34     ll v,w,c;
35     edge*next,*r;
36 }E[maxe],*pt=E,*fir[maxn],*cur[maxn],*rev[maxn];
37 void add(int u,int v,int w,int c){
38     pt->v=v;pt->w=w;pt->c=c;
39     pt->next=fir[u];fir[u]=pt++;
40 }
41 void addedge(int u,int v,int w,int c){
42     add(u,v,w,c);add(v,u,0,-c);
43     fir[u]->r=fir[v];fir[v]->r=fir[u];
44 }
45 bool p[maxn];
46 ll spfa(){
47     queue<int>Q;clr(p);
48     rep(i,S,T) d[i]=-inf;
49     Q.push(S);p[S]=1;d[S]=0;
50     while(!Q.empty()){
51         int x=Q.front();Q.pop();p[x]=0;
52         for(edge*e=fir[x];e;e=e->next) if(e->w){
53             if(d[e->v]<d[x]+e->c){
54                 d[e->v]=d[x]+e->c;
55                 rev[e->v]=e;
56                 if(!p[e->v]){
57                     Q.push(e->v);p[e->v]=1;
58                 }
59             }
60         }
61     }
62     if(d[T]==-inf) return 0;
63     for(edge*e=rev[T];e;e=rev[e->r->v]){
64         e->w-=1;e->r->w+=1;
65     }
66     return d[T];
67 }
68 void Cal(){
69     ll t;
70     while(t=spfa()) ans+=t;
71 }
72 int main(){
73     //freopen("#input.txt","r",stdin);
74     //freopen("#output.txt","w",stdout);
75     n=readint();m=readint();en=readint();S=0;A=n+m+1;T=A+1;
76     rep(i,1,en){
77         int U=readint(),V=readint(),C=readint();
78         addedge(U,n+V,1,C);
79     }
80     rep(i,1,n) addedge(S,i,1,0);
81     rep(i,1,m) addedge(n+i,T,1,0);
82     rep(i,1,n) addedge(i,A,1,0);addedge(A,T,1000009,0);
83     Cal();
84     cout<<ans<<endl;
85     rep(i,1,n){
86         int f=0;
87         for(edge*e=fir[i];e;e=e->next){
88             if(!e->w&&e->v!=A&&e->v!=S) f=e->v-n;
89         }
90         printf("%d",f);putchar(i==n?'\n':' ');
91     }
92     //fclose(stdin);
93     //fclose(stdout);
94     return 0;
95 }
费用流

km 调了一个下午 半个晚上你敢信?先写了一个貌似n^3的n^4 后来膜着tle的代码写出正确n^3 有空再重新复习敲一下

二分图最大权匹配 费用流&KM二分图最大权匹配 费用流&KM
  1 #include<cstdio> 
  2 #include<cstring>
  3 #include<cmath>
  4 #include<ctime>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<set>
  9 #define inf (0x7fffffffll)
 10 #define l(a) ((a)<<1)
 11 #define r(a) ((a)<<1|1)
 12 #define b(a) (1<<(a))
 13 #define rep(i,a,b) for(int i=a;i<=(b);i++)
 14 #define clr(a) memset(a,0,sizeof(a))
 15 typedef long long ll;
 16 typedef unsigned long long ull;
 17 using namespace std;
 18 int readint(){
 19     int t=0,f=1;char c=getchar();
 20     while(!isdigit(c)){
 21         if(c=='-') f=-1;
 22         c=getchar();
 23     }
 24     while(isdigit(c)){
 25         t=(t<<3)+(t<<1)+c-'0';
 26         c=getchar();
 27     }
 28     return t*f;
 29 }
 30 const int maxn=509;
 31 int n,m,en,now,lp[maxn],rp[maxn],pre[maxn],ld[maxn],rd[maxn],a[maxn],w[maxn][maxn],lc[maxn],rc[maxn];;
 32 ll ans;
 33 queue<int>Q;
 34 bool Bfs(){
 35     while(!Q.empty()){
 36         int u=Q.front();Q.pop();
 37         rep(v,1,m) if(rc[v]!=now){
 38             int t=ld[u]+rd[v]-w[u][v];
 39             if(!t){
 40                 pre[v]=u;
 41                 if(!rp[v]){
 42                     int V=v,tmp;
 43                     for(int U=u;V;U=pre[V]){
 44                         tmp=lp[U];lp[U]=V;rp[V]=U;V=tmp;
 45                     }
 46                     return 1;
 47                 }
 48                 rc[v]=now;
 49                 if(lc[rp[v]]!=now){
 50                     lc[rp[v]]=now;Q.push(rp[v]);
 51                 }
 52             }else if(t<a[v]) a[v]=t,pre[v]=u;
 53         }
 54     }
 55     return 0;
 56 }
 57 void KM(){
 58     rep(S,1,n){
 59         rep(i,1,m) a[i]=inf;clr(pre);
 60         while(!Q.empty()) Q.pop();Q.push(S);lc[S]=++now;
 61         for(;;){
 62             if(Bfs()) break;
 63             int del=inf;
 64             rep(i,1,m) if(rc[i]!=now) del=min(del,a[i]);
 65             rep(i,1,n) if(lc[i]==now) ld[i]-=del;
 66             rep(i,1,m) if(rc[i]==now) rd[i]+=del;else if(a[i]<inf) a[i]-=del;
 67             bool flag=0;
 68             rep(i,1,m) if(rc[i]!=now&&!a[i]){
 69                 if(!rp[i]){
 70                     int V=i,tmp;
 71                     for(int U=pre[i];V;U=pre[V]){
 72                         tmp=lp[U];lp[U]=V;rp[V]=U;V=tmp;
 73                     }
 74                     flag=1;break;
 75                 }
 76                 rc[i]=now;
 77                 if(lc[rp[i]]!=now){
 78                     lc[rp[i]]=now;Q.push(rp[i]);//将新增的点加入队列 避免重复的去匈牙利
 79                 }
 80             }
 81             if(flag) break;
 82         }    
 83     }
 84     rep(i,1,m) if(rp[i]) ans+=w[rp[i]][i];
 85     cout<<ans<<endl;
 86     rep(i,1,n){
 87         printf("%d",w[i][lp[i]]?lp[i]:0);
 88         putchar(i==n?'\n':' ');
 89     }
 90 }
 91 int main(){
 92     //freopen("#input.txt","r",stdin);
 93     //freopen("#output.txt","w",stdout);
 94     n=readint();m=readint();en=readint();
 95     if(m<n) m=n;
 96     while(en--){
 97         int u=readint(),v=readint();
 98         w[u][v]=readint();ld[u]=max(ld[u],w[u][v]);
 99     }
100     KM();
101     //fclose(stdin);
102     //fclose(stdout);
103     return 0;
104 }
KM算法 
二分图最大权匹配 费用流&KM二分图最大权匹配 费用流&KM
  1 #include<cstdio> 
  2 #include<cstring>
  3 #include<cmath>
  4 #include<ctime>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<set>
  9 #define inf (0x7fffffff)
 10 #define l(a) ((a)<<1)
 11 #define r(a) ((a)<<1|1)
 12 #define b(a) (1<<(a))
 13 #define rep(i,a,b) for(int i=a;i<=(b);i++)
 14 #define clr(a) memset(a,0,sizeof(a))
 15 typedef long long ll;
 16 typedef unsigned long long ull;
 17 using namespace std;
 18 int readint(){
 19     int t=0,f=1;char c=getchar();
 20     while(!isdigit(c)){
 21         if(c=='-') f=-1;
 22         c=getchar();
 23     }
 24     while(isdigit(c)){
 25         t=(t<<3)+(t<<1)+c-'0';
 26         c=getchar();
 27     }
 28     return t*f;
 29 }
 30 const int maxn=509;
 31 int n,m,en,now,pre[maxn],ld[maxn],rd[maxn],lc[maxn],rc[maxn],lp[maxn],rp[maxn],a[maxn],w[maxn][maxn];
 32 queue<int>Q;
 33 bool Bfs(){
 34     while(!Q.empty()){
 35         int u=Q.front();Q.pop();
 36         rep(v,1,m) if(rc[v]!=now){
 37             int t=ld[u]+rd[v]-w[u][v];//u,v不能写错 
 38             if(!t){
 39                 pre[v]=u;
 40                 if(!rp[v]){
 41                     rp[v]=u;
 42                     int V=v,tmp;
 43                     for(int U=u;V;U=pre[V]){
 44                         tmp=lp[U];lp[U]=V;rp[V]=U;V=tmp;
 45                     }
 46                     return 1;
 47                 }
 48                 rc[v]=now;//注意 
 49                 if(lc[rp[v]]!=now){
 50                     lc[rp[v]]=now;Q.push(rp[v]);
 51                 }
 52             }else if(a[v]>t){
 53                 a[v]=t;pre[v]=u;
 54             }
 55         }
 56     }
 57     return 0;
 58 }
 59 void KM(){
 60     rep(S,1,n){
 61         while(!Q.empty()) Q.pop();
 62         rep(i,1,m) a[i]=inf;clr(pre);
 63         Q.push(S);lc[S]=++now;
 64         for(;;){
 65             bool flag=0;
 66             if(Bfs()) break;
 67             int del=inf;
 68             rep(i,1,m) if(rc[i]!=now) del=min(del,a[i]);
 69             rep(i,1,n) if(lc[i]==now) ld[i]-=del;
 70             rep(i,1,m) if(rc[i]==now) rd[i]+=del;else if(a[i]<inf) a[i]-=del;//理解 
 71             rep(i,1,m) if(rc[i]!=now&&!a[i]){
 72                 if(!rp[i]){
 73                     int V=i,tmp;
 74                     for(int U=pre[i];V;U=pre[V]){
 75                         tmp=lp[U];lp[U]=V;rp[V]=U;V=tmp;
 76                     }
 77                     flag=1;break;
 78                 }
 79                 rc[i]=now;//注意 
 80                 if(lc[rp[i]]!=now){
 81                     lc[rp[i]]=now;Q.push(rp[i]);//将后面的BFS合起来 避免无意义的BFS 
 82                 }
 83             } 
 84             if(flag) break;
 85         }
 86     }
 87     ll ans=0;
 88     rep(i,1,n) if(lp[i]) ans+=w[i][lp[i]];
 89     cout<<ans<<endl;
 90     rep(i,1,n){
 91         printf("%d",w[i][lp[i]]?lp[i]:0);
 92         putchar(i==n?'\n':' ');
 93     }
 94 }
 95 int main(){
 96     //freopen("#input.txt","r",stdin);
 97     //freopen("#output.txt","w",stdout);
 98     n=readint();m=readint();en=readint();
 99     if(m<n) m=n;
100     while(en--){
101         int u=readint(),v=readint();
102         w[u][v]=readint();ld[u]=max(ld[u],w[u][v]);
103     }
104     KM();
105     //fclose(stdin);
106     //fclose(stdout);
107     return 0;
108 }
KM Review

有几个要注意的点!