poj 2195 二分图最优匹配 或 最小费用最大流

就是最基本的二分图最优匹配,将每个人向每个房子建一条边,权值就是他们manhattan距离。然后对所有权值取反,求一次最大二分图最优匹配,在将结果取反就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Maxn 110
using namespace std;
int n;//点的数目
int lx[Maxn],ly[Maxn]; //顶点标号
int weight[Maxn][Maxn];// 边的权值
int slack[Maxn];// Y(i)的松弛函数
int sx[Maxn],sy[Maxn]; //标记X,Y中的顶点是否在交错路径上
int match[Maxn];//Y的匹配
struct Point{
    int x,y;
}house[Maxn],man[Maxn];
int Dis(Point a,Point b)
{
    return abs(a.x-b.x)+abs(a.y-b.y);
}
int dfs(int u)
{
    sx[u]=1;
    int i;
    for(i=1;i<=n;i++)
    {
        if(!sy[i]&&lx[u]+ly[i]==weight[u][i])//如果在相等子图中,且未被访问
        {
            sy[i]=1;
            if(match[i]==-1||dfs(match[i]))
            {
                match[i]=u;
                return 1;
            }
        }
        else
        if(!sy[i])//Y(i)不在交错路径当中
            slack[i]=min(slack[i],lx[u]+ly[i]-weight[u][i]);
    }
    return 0;
}
int bestmatch(bool f)
{
    int i,j;
    if(!f)
    {
        for(i=1;i<=n;i++)
        {
            lx[i]=-0x7FFFFFFF;
            ly[i]=0;
            for(j=1;j<=n;j++)
            {
                weight[i][j]=-weight[i][j];
                lx[i]=max(lx[i],weight[i][j]);
            }
        }
    }
    else
    {
        for(i=1;i<=n;i++)
        {
            lx[i]=0;
            ly[i]=0;
            for(j=1;j<=n;j++)
                lx[i]=max(lx[i],weight[i][j]);
        }
    }
    memset(match,-1,sizeof(match));
    for(i=1;i<=n;i++)
    while(1)
    {
        memset(sx,0,sizeof(sx));
        memset(sy,0,sizeof(sy));
        for(j=0;j<=Maxn-1;j++)
            slack[j]=0x7FFFFFFF;
        if(dfs(i))
            break;
        int dx=0x7FFFFFFF;
        for(j=1;j<=n;j++)
            dx=min(dx,slack[j]);
        for(j=1;j<=n;j++)
        {
            if(sx[j])
                lx[j]-=dx;
            if(sy[j])
                ly[j]+=dx;
        }
    }
    int ans=0;
    for(i=1;i<=n;i++)
        ans+=weight[match[i]][i];
    if(!f)
        ans=-ans;
    return ans;
}
int main()
{
    int i,j,N,M,a,b;
    char str[110];
    while(scanf("%d%d",&N,&M),N||M)
    {
        a=b=0;
        for(i=1;i<=N;i++)
        {
            scanf("%s",&str);
            for(j=0;j<M;j++)
            {
                if(str[j]=='H')
                    house[++a].x=i,house[a].y=j;
                if(str[j]=='m')
                    man[++b].x=i,man[b].y=j;
            }
        }
        n=a;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
                weight[i][j]=Dis(man[i],house[j]);
        }
        printf("%d
",bestmatch(false));
    }
    return 0;
}
View Code

 最小费油最大流解法:

#include<iostream>
#include<cstring>
#include<cstring>
using namespace std;
const int size = 1010;
const int INF = 0x7fffffff;
struct Point{
    int x,y;
};
struct Edge
{
    int to;
    int vol;
    int cost;
    int next;
}e[size*100];
Point house[110],man[110];
int index[size];
int edgeNum;
int pre[size], pos[size];
int dis[size], que[size*10];
bool vis[size];
void insert(int from, int to, int vol, int cost)
{
    e[edgeNum].to = to;
    e[edgeNum].vol = vol;
    e[edgeNum].cost = cost;
    e[edgeNum].next = index[from];
    index[from] = edgeNum++;
    e[edgeNum].to = from;
    e[edgeNum].vol = 0;
    e[edgeNum].cost = -cost;
    e[edgeNum].next = index[to];
    index[to] = edgeNum++;
}
int DIS(Point p1,Point p2)
{
    return abs(p1.x-p2.x)+abs(p1.y-p2.y);
}
bool spfa(int s, int t)
{
    int i;
    memset(pre, -1, sizeof(pre));
    memset(vis, 0, sizeof(vis));
    int head, tail; head = tail = 0;
    for(i = 0; i < size; i++)
        dis[i] = INF;
    que[tail++] = s;
    pre[s] = s;
    dis[s] = 0;
    vis[s] = 1;
    while(head != tail)
    {
        
        int now = que[head++];
        vis[now] = 0;
        for(i = index[now]; i != -1; i = e[i].next)
        {
            int adj = e[i].to;
            if(e[i].vol > 0 && dis[now] + e[i].cost < dis[adj])
            {
                dis[adj] = dis[now] + e[i].cost;
                pre[adj] = now;
                pos[adj] = i;
                if(!vis[adj])
                {
                    vis[adj] = 1;
                    que[tail++] = adj;
                }
            }
        }
    }
    return pre[t] != -1;
}
int MinCostFlow(int s, int t, int flow)
{
    int i;
    int cost = 0;
    flow = 0;
    while(spfa(s, t))
    {
        int f = INF;
        for(i = t; i != s; i = pre[i])
            if (e[pos[i]].vol < f) f = e[pos[i]].vol;
        flow += f; cost += dis[t] * f;
        for(i = t; i != s; i = pre[i])
        {
            e[pos[i]].vol -= f;
            e[pos[i] ^ 1].vol += f;
        }
    }
    return cost; // flow是最大流值
}
int main()
{
    int n,m,i,j,u,v;
    char c;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        memset(index,-1,sizeof(index));
        int k1=0,k2=0;
        for(i=1;i<=n;i++)
        {    
            for(j=1;j<=m;j++)
            {    
                cin>>c;
                switch(c)
                {
                case '.':break;
                case 'm':man[++k1].x=i,man[k1].y=j;break;
                case 'H':house[++k2].x=i,house[k2].y=j;break;
                }
            }
        }
        for(i=1;i<=k1;i++)
        {    for(j=1;j<=k2;j++)
            {
                insert(i,j+k1,1,DIS(man[i],house[j]));
            }
            insert(0,i,1,0);
            insert(i+k1,k1+k2+1,1,0);
        }
        //spfa(0,k1+k2+1);
        int ans=MinCostFlow(0,k1+k2+1,0);
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wangfang20/p/3195438.html