4.2 二分最大权匹配 KM算法模板
类似题目链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2073
陈叔叔题解:http://www.cnblogs.com/njczy2010/p/4384505.html
KM模板(注:如果求的是最小值,main函数初始时取负值,并且out函数输出-KM()即可):
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <queue>
#include <cmath>
#define ll long long
int const N = 35;
int const M = 100005;
int const INF = 0x3f3f3f3f;
ll const mod = 1000000007;
using namespace std;
int T;
int n;
int nx,ny; //两边的点数
int g[N][N]; //二分图描述
int linker[N],lx[N],ly[N]; //y中各点匹配状态,x,y中的点标号
int slack[N];
bool visx[N],visy[N];
bool DFS(int x)
{
visx[x] = true;
for(int y = 0;y < ny;y++)
{
if(visy[y]) continue;
int tmp = lx[x] + ly[y] -g[x][y];
if(tmp == 0)
{
visy[y] = true;
if(linker[y] == -1 || DFS(linker[y]))
{
linker[y] = x;
return true;
}
}
else if(slack[y] > tmp)
slack[y] = tmp;
}
return false;
}
int KM()
{
memset(linker,-1,sizeof(linker));
memset(ly,0,sizeof(ly));
for(int i = 0;i < nx;i++)
{
lx[i] = -INF;
for(int j = 0;j < ny;j++)
if(g[i][j] > lx[i])
lx[i] = g[i][j];
}
for(int x =0;x < nx;x++)
{
for(int i = 0;i < ny ;i++)
slack[i] = INF;
while(true)
{
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
if(DFS(x)) break;
int d = INF;
for(int i = 0;i < ny;i++)
if(!visy[i] && d > slack[i])
d = slack[i];
for(int i = 0 ; i < nx ;i++)
if(visx[i])
lx[i] -= d;
for(int i = 0 ; i < ny ;i++)
{
if(visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
}
int res = 0;
for(int i = 0;i < ny ;i++)
if(linker[i] != -1)
res += g[ linker[i] ][i];
return res;
}
void ini()
{
scanf("%d",&n);
int i,j;
for(i = 0;i < n;i++){
for(j = 0;j < n;j++)
scanf("%d",&g[i][j]);
}
nx = ny =n;
}
void solve()
{
}
void out()
{
printf("%d\n",KM());
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
scanf("%d",&T);
//for(int cnt=1;cnt<=T;cnt++)
while(T--)
//while(scanf("%d%d%d",&a,&b,&n)!=EOF)
{
ini();
solve();
out();
}
}
4.3 最小费用最大流
大大2135题解链接:poj2135 - 金海峰 - 博客园
算法模板:POJ2135可转化,有点像中国邮递员问题
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define typef int
#define typec int
#define maxn 1005
#define maxm 10005
#define N maxn + 2
#define E maxm * 4 + 4
const typef inff = 0x3f3f3f3f;
const typec infc = 0x3f3f3f3f;
struct network
{
int nv, ne, pnt[E], nxt[E];
int vis[N], que[N], head[N], pv[N], pe[N];
typef flow, cap[E];
typec cost, dis[E], d[N];
void addedge(int u, int v, typef c, typec w)
{
pnt[ne] = v;
cap[ne] = c;
dis[ne] = +w;
nxt[ne] = head[u];
head[u] = (ne++);
pnt[ne] = u;
cap[ne] = 0;
dis[ne] = -w;
nxt[ne] = head[v];
head[v] = (ne++);
}
int mincost(int src, int sink)
{
int i, k, f, r;
typef mxf;
for (flow = 0, cost = 0;;)
{
memset(pv, -1, sizeof(pv));
memset(vis, 0, sizeof(vis));
for (i = 0; i < nv; ++i)
d[i] = infc;
d[src] = 0;
pv[src] = src;
vis[src] = 1;
for (f = 0, r = 1, que[0] = src; r != f;)
{
i = que[f++];
vis[i] = 0;
if (N == f)
f = 0;
for (k = head[i]; k != -1; k = nxt[k])
if (cap[k] && dis[k] + d[i] < d[pnt[k]])
{
d[pnt[k]] = dis[k] + d[i];
if (0 == vis[pnt[k]])
{
vis[pnt[k]] = 1;
que[r++] = pnt[k];
if (N == r)
r = 0;
}
pv[pnt[k]] = i;
pe[pnt[k]] = k;
}
}
if (-1 == pv[sink])
break;
for (k = sink, mxf = inff; k != src; k = pv[k])
if (cap[pe[k]] < mxf)
mxf = cap[pe[k]];
flow += mxf;
cost += d[sink] * mxf;
for (k = sink; k != src; k = pv[k])
{
cap[pe[k]] -= mxf;
cap[pe[k] ^ 1] += mxf;
}
}
return cost;
}
void build(int v, int e)
{
nv = v;
ne = 0;
memset(head, -1, sizeof(head));
int x, y;
typec w;
for (int i = 0; i < e; ++i)
{
scanf("%d%d%d", &x, &y, &w);
addedge(x, y, 1, w);// add arc (u->v, f, w)
addedge(y, x, 1, w);
}
addedge(0, 1, 2, 0);
addedge(v - 2, v - 1, 2, 0);
}
} g;
int n, m;
int main()
{
//freopen("t.txt", "r", stdin);
scanf("%d%d", &n, &m);
g.build(n + 2, m);
printf("%d\n", g.mincost(0, n + 1));
return 0;
}
/*
4 5
1 2 1
2 3 1
3 4 1
1 3 2
2 4 2
*/