有m个插座,n个电器,每个插座最多可连接一个电器。另外有一个插头,可以使得一个插座连接三个电器,问最大匹配数是多少。
二分图:二分图做法相对简洁一些,也会更快,保存原先的最大匹配,枚举每个插座是否还存在增广路。每次就是要对原图的反复复制。
#include
#include
#include
#include
#include
using namespace std;
const int N=1e5+7;
const int inf=1<<26;
struct Edge{
int u,v,nxt;
Edge(int u=0,int v=0,int nxt=0):u(u),v(v),nxt(nxt){}
}edge[30*N];
int n,m,k,edn;
int p[N],d[N],c[N];
void add(int u,int v){
edge[++edn]=Edge(u,v,p[u]);p[u]=edn;
}
int match[N],vis[N],tmp[N];
bool dfs(int u){
for(int i=p[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(vis[v]) continue;vis[v]=1;
if(match[v]==-1||dfs(match[v])){
match[v]=u;
return true;
}
}
return false;
}
int main()
{
memset(p,-1,sizeof(p));edn=-1;
scanf("%d%d%d",&n,&m,&k);
int u,v;
for(int i=1;i<=k;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
int maxn=0;
memset(match,-1,sizeof(match));
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(dfs(i)) maxn++;
}
memcpy(tmp,match,sizeof(match));
int ans=0;
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=1;j<=2;j++){
memset(vis,0,sizeof(vis));
if(dfs(i)) cnt++;
else break;
}
ans=max(ans,cnt);
memcpy(match,tmp,sizeof(tmp));
}
printf("%d\n",ans+maxn);
return 0;
}
网络流:网络流其实没那么必要,各种复杂度都很大。
先跑一遍容量都为1的dinic,然后枚举插座多给两个容量,在残余网络中跑。
麻烦的是网络流如果直接复制原图,那么加上本身的复杂度会TLE。但也可以发现每次我只增加了2个容量,相对于原来的残留网络变化其实不大,只要把这些变化的流量记录在一个数组里,逐一退回即可。
#include
#include
#include
#include
#include
using namespace std;
const int N=1e5+7;
const int inf=1<<26;
struct Edge{
int u,v,w,nxt;
Edge(int u=0,int v=0,int w=0,int nxt=0):u(u),v(v),w(w),nxt(nxt){}
}edge[30*N];
int n,m,k,edn,sp,tp;
int p[N],d[N],c[N];
void add(int u,int v,int w){
edge[++edn]=Edge(u,v,w,p[u]);p[u]=edn;
edge[++edn]=Edge(v,u,0,p[v]);p[v]=edn;
}
bool bfs(){
memset(d,-1,sizeof(d));d[sp]=0;
queueq;q.push(sp);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=p[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(d[v]==-1&&edge[i].w){
d[v]=d[u]+1;
q.push(v);
if(v==tp) return true;
}
}
}
return ~d[tp];
}
struct chg{
int id,val;
}cg[N*2];
int top;
int dfs(int u,int b){
if(u==tp) return b;
int r=0;
for(int i=c[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(edge[i].w&&d[v]==d[u]+1){
int x=min(edge[i].w,b-r);
c[u]=i;
x=dfs(v,x);
r+=x;
edge[i].w-=x;
edge[i^1].w+=x;
cg[++top].id=i;
cg[top].val=x;
if(r==b) break;
}
}
if(!r)d[u]=-2;
return r;
}
int dinic(){
int total=0,t;
while(bfs()){
memcpy(c,p,sizeof(p));
while(t=dfs(sp,inf))
total+=t;
}
return total;
}
int main()
{
memset(p,-1,sizeof(p));edn=-1;
scanf("%d%d%d",&n,&m,&k);
sp=n+m+1,tp=sp+1;
int u,v;
for(int i=1;i<=k;i++){
scanf("%d%d",&u,&v);
add(u,v+n,1);
}
for(int i=1;i<=n;i++)
add(sp,i,1);
for(int i=1;i<=m;i++)
add(i+n,tp,1);
int ans=dinic(),tmp=0;
for(int j=1;j<=n;j++){
top=0;
add(sp,j,2);
tmp=max(tmp,dinic());
for(int i=1;i<=top;i++){
int id=cg[i].id;
int val=cg[i].val;
edge[id].w+=val;
edge[id^1].w-=val;
}
p[sp]=edge[p[sp]].nxt;
p[j]=edge[p[j]].nxt;
edn-=2;
}
printf("%d\n",ans+tmp);
return 0;
}