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\n",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\n",ans);

    }

    return 0;

}

 

你可能感兴趣的:(poj)