~~~~~~~~~~~~~~~~~~~~~~~~~~~以下是最大匹配~~~~~~~~~~~~~~~~~~~~~~~~~~~~
参考:http://blog.csdn.net/hackbuteer1/article/details/7398008
点覆盖数+点独立数=n
边覆盖数+边独立数(匹配)=n
点覆盖数=边独立数(匹配)
//algo1:
//simplified_newflow
//O(n*m)
struct simplified_newflow{
int nx,ny,m,ans;
int cy[N],cx[N],vis[N];
vector<int > G[N];
void init(int x,int y)
{
nx=x; ny=y;
for (int i=0;i<nx;i++) G[i].clear();
}
int path(int u)
{ for (int i=0;i<G[u].size();i++)
if (!vis[G[u][i]])
{ int v=G[u][i];
vis[v]=1;
if (cy[v]==-1||path(cy[v]))
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
return 0;
}
int MaxMatch()
{ int ans=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
for (int i=0;i<nx;i++)
if (cx[i]==-1)
{ memset(vis,0,sizeof(vis));
ans+=path(i);
}
return ans;
}
}it;
//algo2:
//Hopcroft_Carp
//O(n^(1/2)*m)
struct Hopcroft_Carp{
vector<int > g[N];
int Mx[N],My[N],nx,ny;
int dx[N],dy[N],dis;
bool vst[N],T[N];
void init(int x,int y)
{
nx=x; ny=y;
for (int i=0;i<nx;i++) g[i].clear();
}
void AddEdge(int u,int v)
{
g[u].pb(v);
}
bool searchP()
{
queue<int>Q; dis=INF;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=0;i<nx;i++)
if(Mx[i]==-1)
{
Q.push(i);
dx[i]=0;
}
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(dx[u]>dis) break;
for(int i=0;i<g[u].size(); i++)
if(dy[g[u][i]]==-1)
{ int v=g[u][i];
dy[v]=dx[u]+1;
if(My[v]==-1) dis=dy[v];
else
{
dx[My[v]]=dy[v]+1;
Q.push(My[v]);
}
}
}
return dis!=INF;
}
bool DFS(int u)
{
for(int i=0;i<g[u].size(); i++)
{ int v=g[u][i];
if(vst[v]||dy[v]!=dx[u]+1)continue;
vst[v]=1;
if(My[v]!=-1&&dy[v]==dis) continue;
if(My[v]==-1||DFS(My[v]))
{
My[v]=u;
Mx[u]=v;
return 1;
}
}
return 0;
}
int MaxMatch()
{
int res=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(searchP())
{
memset(vst,0,sizeof(vst));
for(int i=0;i<nx;i++)
if(Mx[i]==-1&&DFS(i)) res++;
}
return res;
}
}it;
~~~~~~~~~~~~~~~~~~~~~~~~~~~以下是最大权匹配~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//KM最大权匹配模板:
//[建议]求最小权方法一:Addedge边取反且最后答案取反
//求最小权方法二:按注释@……@部分改
typedef double typ;
const typ INF=1e8;
struct KM_{
int nx,ny;
typ E[?][?],lx[N],ly[N],slk[N];
int link[N],lin[N];
bool visx[N],visy[N];
bool DFS(int u)
{
visx[u]=true;
for(int v=0;v<ny;++v)
{
if(visy[v])continue;
typ t=lx[u]+ly[v]-E[u][v];
if(t>eps) //t>0 如果typ为int
//@t<-eps@
{minimize(slk[v],t);continue;} //@maximize@
visy[v]=1;
if(link[v]==-1||DFS(link[v])){link[v]=u;lin[u]=v;return true;}
}
return false;
}
typ KM()
{
CLR(ly,0);
CLR(link,-1);
CLR(lin,-1);
for(int i=0;i<nx;++i)lx[i]=*max_element(E[i],E[i]+ny);//@min_element@
for(int u=0;u<nx;++u)
{ fill_n(slk,ny,INF); //@fill_n(slk,ny,-INF);@
while(1)
{
CLR(visx,0);
CLR(visy,0);
if(DFS(u))break;
typ temp=INF; //temp=-INF;@
for(int v=0;v<ny;++v)if(!visy[v]) minimize(temp,slk[v]); //@maximize@
if (temp==INF) return (#-1#);
for(int i=0;i<nx;++i)if(visx[i])lx[i]-=temp;
for(int v=0;v<ny;++v)if(visy[v])ly[v]+=temp;else slk[v]-=temp;
}
}
typ ret=0;
for(int j=0;j<nx;++j)if (lin[j]!=-1)ret+=E[j][lin[j]];
return ret;
}
void init(int x,int y)
{ nx=x; ny=y;
CLR(E,0);
}
void AddEdge(int x,int y,typ z)
{ E[x][y]=z;
}
}it;
~~~~~~~~~~~~~~~~~~~~~~~~~~~以下是带匹配数限制的最大权匹配~~~~~~~~~~~~~~~~~~~~~~~~~~~~