POJ-2195-Going Home

比较裸地最小费用流题,对每个人对每个房子进行连容量为1的边,然后设定源点,并向所有的人连费用为0,容量为1的边,然后设定汇点,房子向汇点连容量为1费用为0的边。然后跑最小费用流

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
const int inf=1<<29;
const int maxn=1e4+100;
const int maxm=2e5;
struct Node
{
    int x;
    int y;
    Node(){}
    Node(int sx,int sy)
    {
        x=sx;
        y=sy;
    }
}P[maxn],H[110];
int e,st,des,head[maxn],nxt[maxm],cost[maxm],flow[maxm],pnt[maxm],dist[maxn],pre[maxn];
int n,m,a[110][110],ho_id,pep_id;
bool vis[maxn];
queue<int> q;
char map[110][110];
void AddEdge(int u,int v,int c,int f)
{
    pnt[e]=v;nxt[e]=head[u];cost[e]=c;flow[e]=f;head[u]=e++;
    pnt[e]=u;nxt[e]=head[v];cost[e]=-c;flow[e]=0;head[v]=e++;
}
bool Spfa(int st,int des)
{
    for(int i=st;i<=des;i++)
    {
        dist[i]=inf;
        pre[i]=-1;
    }
    dist[st]=0;
    q.push(st);
    while(!q.empty())
    {
        int u=q.front();
        vis[u]=0;
        q.pop();
        for(int i=head[u];i!=-1;i=nxt[i])
            if(flow[i]&&dist[pnt[i]]>dist[u]+cost[i])
            {
                dist[pnt[i]]=dist[u]+cost[i];
                pre[pnt[i]]=i;
                if(!vis[pnt[i]])
                {
                    vis[pnt[i]]=1;
                    q.push(pnt[i]);
                }
            }
    }
    return dist[des]!=inf;
}
int mincostflow()
{
    int ans=0;
    while(Spfa(st,des))
    {
        int mini=inf;
        for(int i=pre[des];i!=-1;i=pre[pnt[i^1]])
            mini=min(mini,flow[i]);
        for(int i=pre[des];i!=-1;i=pre[pnt[i^1]])
        {
            flow[i]-=mini;
            flow[i^1]+=mini;
        }
        ans+=mini*dist[des];
    }
    return ans;
}
void Build()
{
    e=st=0;des=pep_id+ho_id+1;
    memset(head,-1,sizeof(head));
    for(int i=0;i<pep_id;i++)
    {
        AddEdge(st,i+1,0,1);
        for(int j=0;j<ho_id;j++)
            AddEdge(i+1,pep_id+1+j,abs(P[i].x-H[j].x)+abs(P[i].y-H[j].y),1);
    }
    for(int i=0;i<ho_id;i++)
        AddEdge(pep_id+i+1,des,0,1);
}
void solve()
{
    Build();
    printf("%d\n",mincostflow());
}
int main()
{
    while(scanf("%d%d",&n,&m)&&(n+m))
    {
        ho_id=pep_id=0;
        memset(a,0,sizeof(a));
        for(int i=0;i<n;i++)
            scanf("%s",map[i]);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            {
                if(map[i][j]=='m')
                    P[pep_id++]=Node(i,j);
                if(map[i][j]=='H')
                    H[ho_id++]=Node(i,j);
            }
        solve();
    }
    return 0;
}


你可能感兴趣的:(最小费用流)