POJ 2195 Going Home | 带权二分图匹配

给个地图有人和房子

保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价

问让人都住在房子里最小代价


显然是个带权二分图最大匹配

转化成以一个网络,规定w是容量,c是代价

1.S向人连边,w=1,c=0

2.房子向T连边,w=1,c=0

3.人向房子连边 w=1,c=距离

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define N 10000
#define INF 1000000000
using namespace std;
deque <int> q;
int head[N],lev[N],dist[N],n,m,ecnt=1,vis[N],S,T,ans,H,M;
char mp[110][110];
struct adj
{
    int nxt,v,w,c;
}e[200*200];
int Abs(int x)
{return x>0?x:-x;}
struct coor
{
    int x,y;
    int operator - (const coor &a)const
	{return Abs(x-a.x)+Abs(y-a.y);}
};
coor make(int x,int y)
{
    coor ret;
    ret.x=x,ret.y=y;
    return ret;
}
vector <coor> house,man;
inline void add(int u,int v,int w,int c)
{
    e[++ecnt].v=v,e[ecnt].w=w,e[ecnt].c=c,e[ecnt].nxt=head[u],head[u]=ecnt;
    e[++ecnt].v=u,e[ecnt].w=0,e[ecnt].c=-c,e[ecnt].nxt=head[v],head[v]=ecnt;
}
inline int spfa(int s,int t)
{
    int v;
    memset(vis,0,sizeof(vis));
    for (int i=s;i<=t;i++) dist[i]=INF;
    dist[t]=0,vis[t]=1;
    q.push_back(t);
    while (!q.empty())
    {
    int u=q.front();q.pop_front();
    for (int i=head[u];i;i=e[i].nxt)
        if (e[i^1].w>0 && dist[v=e[i].v]>dist[u]-e[i].c)
        {
        dist[v]=dist[u]-e[i].c;
        if (!vis[v])
        {
            vis[v]=1;
            if (!q.empty() && dist[v]<dist[q.front()])
            q.push_front(v);
            else
            q.push_back(v);
        }
        }
    vis[u]=0;
    }
    return dist[s]<INF;
}
inline int dfs(int x,int flow)
{
    if (x==T)
    return vis[T]=1,flow;
    int used=0,tmp,v;
    vis[x]=1;
    for (int i=head[x];i;i=e[i].nxt)
    if (!vis[v=e[i].v] && e[i].w>0 && dist[x]-e[i].c==dist[v])
    {
        tmp=dfs(v,min(e[i].w,flow-used));
        if (tmp>0)
        ans+=tmp*e[i].c,e[i].w-=tmp,e[i^1].w+=tmp,used+=tmp;
        if (used==flow) break;
    }
    return used;
}
inline int CostFlow()
{
    int Flow=0;
    while (spfa(S,T))
    {
	vis[T]=1;
	while (vis[T])
	{
	    memset(vis,0,sizeof(vis));
	    Flow+=dfs(S,INF);
	}
    }
    return Flow;
}
void init()
{
    memset(head,0,sizeof(head));
    man.clear();
    house.clear();
    ans=M=H=0;
    ecnt=1;
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
	if (n==0 && m==0) break;
	init();
	for (int i=1;i<=n;i++)
	    scanf("%s",mp[i]+1);
	for (int i=1;i<=n;i++)
	    for (int j=1;j<=m;j++)
		if (mp[i][j]=='m')
		    man.push_back(make(i,j)),M++;
		else if (mp[i][j]=='H')
		    house.push_back(make(i,j)),H++;
	T=H+M+1;
	for (int i=0;i<M;i++)
	    for (int j=0;j<H;j++)
		add(i+1,M+j+1,1,man[i]-house[j]);
	for (int i=1;i<=M;i++)
	    add(S,i,1,0);
	for (int i=1;i<=H;i++)
	    add(M+i,T,1,0);
       CostFlow();
	printf("%d
",ans);
    }
	
    return 0;
}
原文地址:https://www.cnblogs.com/mrsheep/p/7954010.html