二分图匹配
匈牙利算法
练习题
过山车 HDU - 2063(二分图匹配)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063
题意:每个女生有自己喜欢的男生的列表,问最多能够组成几对?
匈牙利算法
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=500+10;
int k,m,n;
int match[maxn],visit[maxn];
vector<int> G[maxn];
bool dfs(int u)
{
for(auto v : G[u])
{
if(visit[v]) continue;
visit[v]=true;
if(!match[v]||dfs(match[v]))
{
match[v]=u;
return true;
}
}
return false;
}
int main()
{
while(scanf("%d",&k)&&k)
{
scanf("%d%d",&m,&n);
for(int i=1;i<=m;++i) G[i].clear();
memset(match,0,sizeof(match));
for(int i=1;i<=k;++i)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
}
int ans=0;
for(int i=1;i<=m;++i)
{
memset(visit,0,sizeof(visit));
if(dfs(i)) ans++;
}
printf("%d\n",ans);
}
return 0;
}
最大流二分图匹配
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5,maxm=1e6+5;
const int mod=1e9+7,inf=0x7f7f7f7f;
namespace Dinic
{
const int MAXN=1e6+10,MAXM=1e6+10;
int head[MAXN],cur[MAXN],cnt;
int depth[MAXN];
int maxvex;//点的数量
struct Edge
{
int nxt,to,flow;
}edges[MAXM<<1];
void init(int n)
{
maxvex=n;
cnt=-1;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int flow)
{
edges[++cnt]={head[u],v,flow};
head[u]=cnt;
edges[++cnt]={head[v],u,0};
head[v]=cnt;
}
bool bfs(int s,int t)
{
for(int i=0;i<=maxvex;++i)
cur[i]=head[i],depth[i]=inf;
queue<int> q;
q.push(s);
depth[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=edges[i].nxt)
{
int v=edges[i].to,flow=edges[i].flow;
if(depth[v]==inf&&flow)
{
depth[v]=depth[u]+1;
q.push(v);
}
}
}
return depth[t]<inf;
}
int dfs(int u,int t,int curflow)//当前边的流
{
if(curflow==0||u==t)
return curflow;
int flow=0,f;
for(int i=cur[u];i!=-1;i=edges[i].nxt)
{
cur[u]=i;//当前弧优化
int v=edges[i].to,eflow=edges[i].flow;
if(depth[v]==depth[u]+1&&(f=dfs(v,t,min(curflow,eflow))))
{
flow+=f;
curflow-=f;
edges[i].flow-=f;
edges[i^1].flow+=f;
if(curflow==0)
break;
}
}
return flow;
}
int Maxflow(int s,int t)
{
int cnt=0;
int flow=0,f;
while(bfs(s,t))
while((f=dfs(s,t,inf))>0)
flow+=f;
return flow;
}
};
using namespace Dinic;
int k,m,n;
int main()
{
while(scanf("%d",&k)&&k)
{
scanf("%d%d",&m,&n);
Dinic::init(m+n+1);
for(int i=1;i<=m;++i)
Dinic::add(0,i,1);
for(int i=1;i<=n;++i)
Dinic::add(m+i,m+n+1,1);
for(int i=1;i<=k;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v+m,1);
}
int ans=Dinic::Maxflow(0,m+n+1);
printf("%d\n",ans);
}
return 0;
}
P3386 【模板】二分图最大匹配
匈牙利算法模板
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=500+10;
int k,m,n,e;
int match[maxn],visit[maxn];
vector<int> G[maxn];
bool dfs(int u)
{
for(auto v : G[u])
{
if(visit[v]) continue;
visit[v]=true;
if(!match[v]||dfs(match[v]))
{
match[v]=u;
return true;
}
}
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
memset(match,0,sizeof(match));
for(int i=1;i<=e;++i)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
}
int ans=0;
for(int i=1;i<=n;++i)
{
memset(visit,0,sizeof(visit));
if(dfs(i)) ans++;
}
printf("%d\n",ans);
return 0;
}
KM算法
最大权匹配
参考链接:https://www.cnblogs.com/logosG/p/logos.html
参考链接:https://www.cnblogs.com/jackge/archive/2013/05/03/3057028.html
参考链接:https://www.cnblogs.com/wenruo/p/5264235.html
练习题
奔小康赚大钱 HDU - 2255 (KM算法)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=300+10;
const int inf=0x3f3f3f3f;
int n;
int match[maxn],visit[maxn];
int pre[maxn],slack[maxn],lx[maxn],ly[maxn],w[maxn][maxn];
void bfs(int u)
{
ll x,y=0,yy=0,d;
memset(visit,0,sizeof(visit));
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;++i) slack[i]=inf;
match[y]=u;
while(1)
{
x=match[y],d=inf,visit[y]=1;
for(int i=1;i<=n;++i)
{
if(!visit[i])
{
if(slack[i]>lx[x]+ly[i]-w[x][i])
{
slack[i]=lx[x]+ly[i]-w[x][i];
pre[i]=y;
}
if(slack[i]<d)
d=slack[i],yy=i;
}
}
for(int i=0;i<=n;++i)
if(visit[i])
lx[match[i]]-=d,ly[i]+=d;
else
slack[i]-=d;
y=yy;
if(match[y]==-1)
break;
}
while(y)
match[y]=match[pre[y]],y=pre[y];
}
int km()
{
memset(match,-1,sizeof(match));
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(int i=1;i<=n;++i) bfs(i);
int ans=0;
for(int i=1;i<=n;++i)
if(match[i]!=-1)
ans+=w[match[i]][i];
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
scanf("%d",&w[i][j]);
int ans=km();
printf("%d\n",ans);
}
return 0;
}
J. Spy (KM模板)2019 ICPC Asia Nanjing Regional
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=400+10;
const int inf=9e18;
int n;
ll a[maxn],p[maxn],b[maxn],c[maxn];
int match[maxn],visit[maxn];
ll pre[maxn],slack[maxn],lx[maxn],ly[maxn],w[maxn][maxn];
void bfs(int u)
{
ll x,y=0,yy=0,d;
memset(visit,0,sizeof(visit));
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;++i) slack[i]=inf;
match[y]=u;
while(1)
{
x=match[y],d=inf,visit[y]=1;
for(int i=1;i<=n;++i)
{
if(!visit[i])
{
if(slack[i]>lx[x]+ly[i]-w[x][i])
{
slack[i]=lx[x]+ly[i]-w[x][i];
pre[i]=y;
}
if(slack[i]<d)
d=slack[i],yy=i;
}
}
for(int i=0;i<=n;++i)
if(visit[i])
lx[match[i]]-=d,ly[i]+=d;
else
slack[i]-=d;
y=yy;
if(match[y]==-1)
break;
}
while(y)
match[y]=match[pre[y]],y=pre[y];
}
ll km()
{
memset(match,-1,sizeof(match));
for(int i=1;i<=n;++i) bfs(i);
ll ans=0;
for(int i=1;i<=n;++i)
if(match[i])
ans+=w[match[i]][i];
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<=n;++i) scanf("%lld",&p[i]);
for(int i=1;i<=n;++i) scanf("%lld",&b[i]);
for(int i=1;i<=n;++i) scanf("%lld",&c[i]);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
for(int k=1;k<=n;++k)
if(b[i]+c[j]>a[k])
w[i][j]+=p[k];
ll ans=km();
printf("%lld\n",ans);
return 0;
}