二分图总结
1. 二分图的判定:染色法。\(O(n+m)\)
void dfs(int x)
{
int i,j;
for(i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(!c[to])
{
c[to]=3-c[x];
dfs(to);
}
else if(c[to]==c[x])
{
pd=0;
return;
}
}
}
2. 二分图最大匹配:
匈牙利算法(增广路算法): \(O(n*m)\)
dinic(网络流算法):\(O(\sqrt n*m)\)
bool dfs(int x)
{
int i,j;
vis[x]=1;
for(i=head[x];i;i=a[i].nxt)
{
int to=a[i].to;
if(vis[to]) continue;
vis[to]=1;
if(!match[to]||dfs(match[to]))
{
match[to]=x;
return true;
}
}
return false;
}
for(i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++;
}
3. 最小点覆盖=最大匹配
4. 最大独立集=总点数-最大匹配
5. 有向无环图中:
a. 最小边覆盖=最小路径点覆盖:
选取最少的路径,使得每个定点均属于一条路径,路径长度可以为0。
与二分图的关系:将每个点拆成入点和出点,最小路径覆盖=原图总点数-拆点后的图的最大匹配
b. 最大团:任意两点之间都有边相连的最大子图
无向图\(G\)的最大团等于它补图的最大独立集。
c. 最小路径可重点覆盖
有向无环图\(G\)的最小路径可重点覆盖,等价于先对有向图传递闭包,得到有向无环图\(G'\),再在\(G'\)上求一般的(路径不可相交的)最小路径点覆盖。
6. 可用网络流dinic求解
例:「UVA1411」Ants:
因为两条相交线段长度必然大于分别直接相连,所以答案就是二分图上跑最小费用流,使用类dinic算法,时间复杂度上届为\(O(nmf)\),\(f\)为流量。
#include<bits/stdc++.h>
#define ll long long
#define N 500
#define M 600000
#define eps 1e-5
using namespace std;
int head[N],n,cnt=2,S,T,inf=1e9+7,vis[N];
struct note{
double x,y;
}b[N],W[N];
struct edge{
int to,nxt,sz;
double w;
}a[M];
void add(int x,int y,int s,double z)
{
a[cnt].to=y;
a[cnt].sz=s;
a[cnt].nxt=head[x];
a[cnt].w=z;
head[x]=cnt++;
if(s!=0) add(y,x,0,-z);
}
double calc(note x,note y){
return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
int ans=inf;
double dis[N];
deque<int> q;
bool spfa()
{
int i,j;
memset(vis,0,sizeof(vis));
for(i=S;i<=T;i++) dis[i]=inf;
while(!q.empty()) q.pop_front();
q.push_back(S);dis[S]=0;
vis[S]=1;
while(!q.empty())
{
int now=q.front();q.pop_front();
vis[now]=0;
for(i=head[now];i;i=a[i].nxt)
{
int to=a[i].to;
if(a[i].sz&&dis[to]-dis[now]-a[i].w>eps)
{
dis[to]=dis[now]+a[i].w;
if(!vis[to])
{
vis[to]=1;
if(!q.empty()&&dis[to]<dis[q.front()]) q.push_front(to);
else q.push_back(to);
}
}
}
}
return dis[T]!=inf;
}
int cur[N];
int cost=0,maxflow;
int dinic(int x,int flow)
{
int i,j,sum=0;
vis[x]=1;
if(x==T||!flow) return flow;
for(i=cur[x];i;i=a[i].nxt)
{
cur[x]=i;
int to=a[i].to;
if(fabs(dis[to]-dis[x]-a[i].w)<eps&&a[i].sz&&!vis[to])
{
int f=dinic(to,min(a[i].sz,flow-sum));
if(!f) continue;
sum+=f;
a[i].sz-=f;
a[i^1].sz+=f;
cost+=f*a[i].w;
if(!flow) break;
}
}
return sum;
}
void solve()
{
while(spfa())
{
vis[T]=1;
while(vis[T])
{
memcpy(cur,head,sizeof(head));
memset(vis,0,sizeof(vis));
maxflow+=dinic(S,inf);
ans=min(ans,cost);
}
}
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%lf%lf",&b[i].x,&b[i].y);
for(i=1;i<=n;i++) scanf("%lf%lf",&W[i].x,&W[i].y);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
// if(i==j) continue;
double D=calc(b[i],W[j]);
add(i,j+n,1,D);
}
}
S=0,T=2*n+1;
for(i=1;i<=n;i++)
{
add(S,i,1,0);
add(i+n,T,1,0);
}
solve();
for(i=1;i<=n;i++)
{
for(j=head[i];j;j=a[j].nxt)
{
int to=a[j].to;
if(!a[j].sz)
{
printf("%d\n",to-n);
break;
}
}
}
return 0;
}