1. 程式人生 > >網路流之最小費用最大流

網路流之最小費用最大流

具體思路:建好圖之後,每一次從源點到匯點走最短路,如果能走到就加上,如果走不到就停止。具體注意細節在程式碼中解釋。

AC程式碼:

#include<iostream>
#include<string>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<stdio.h>
#include<algorithm>
using namespace std;
# define inf 0x3f3f3f3f
# define ll long long
# define maxn 100000+10
struct point
{
    int x,y;
} H[maxn],M[maxn];
char str[100][100];
int head[maxn];//前向星的建立。
int num;
int pree[maxn];//記錄該點前一個連的點。
int prev[maxn];//記錄該點位於前向星的哪一條邊上。
int vis[maxn];
int dist[maxn];//記錄距離
struct node
{
    int to;
    int w;
    int cost;
    int nex;
} edge[maxn];
void addage(int fr,int to,int w,int cost)
{
    edge[num].to=to;
    edge[num].w=w;
    edge[num].cost=cost;
    edge[num].nex=head[fr];
    head[fr]=num++;
    edge[num].to=fr;//反向邊的建立,方向相反,流量為0,話費為原來花費的負數。
    edge[num].w=0;
    edge[num].cost=-cost;
    edge[num].nex=head[to];
    head[to]=num++;
}
bool spfa(int st,int ed)
{
    memset(vis,0,sizeof(vis));
    memset(dist,inf,sizeof(dist));
    memset(pree,-1,sizeof(pree));
    queue<int>q;
    vis[st]=1;
    dist[st]=0;
    q.push(st);
    while(!q.empty())
    {
        int top=q.front();
        q.pop();
        vis[top]=0;
        for(int i=head[top]; i!=-1; i=edge[i].nex)
        {
            int temp=edge[i].to;
            if(edge[i].w>0&&dist[temp]>dist[top]+edge[i].cost)//求最短路的過程,注意dist數組裡存的是花費,不是流量。
            {
                dist[temp]=dist[top]+edge[i].cost;
                pree[temp]=top;
                prev[temp]=i;
                if(vis[temp]==0)
                {
                    vis[temp]=1;
                    q.push(temp);
                }
            }
        }
    }
    return pree[ed]!=-1;
}
int mincostflow(int st,int ed)
{
    int ans=0;
    while(spfa(st,ed))
    {
        int minn=inf;
        for(int i=ed; i!=st; i=pree[i])
        {
            minn=min(minn,edge[prev[i]].w);
        }
        ans+=dist[ed]*minn;
        for(int i=ed; i!=st; i=pree[i])
        {
            edge[prev[i]].w-=minn;
            edge[prev[i]^1].w+=minn;
        }
    }
    return ans;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)&&(m+n))
    {
        num=0;
        memset(head,-1,sizeof(head));
        for(int i=1; i<=n; i++)
        {
            scanf("%s",str[i]+1);
        }
        int t1=0,t2=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(str[i][j]=='H')
                {
                    H[++t1].x=i;
                    H[t1].y=j;
                }
                else if(str[i][j]=='m')
                {
                    M[++t2].x=i;
                    M[t2].y=j;
                }
            }
        }
        for(int i=1; i<=t1; i++)
        {
            for(int j=1; j<=t1; j++)
            {
                addage(i,t1+j,1,abs(M[i].x-H[j].x)+abs(M[i].y-H[j].y));
            }
        }
        int st=0,ed=t1+t1+1;
        for(int i=1; i<=t1; i++)
        {
            addage(st,i,1,0);//源點到學生流量為1,花費為0
        }
        for(int i=1; i<=t1; i++)
        {
            addage(t1+i,ed,1,0);//同理
        }
        int ans=mincostflow(st,ed);
        printf("%d\n",ans);
    }
    return 0;
}