POJ 2195 Going Home 最小费用最大流(模板题)

来源:互联网 发布:java decompiler使用 编辑:程序博客网 时间:2024/05/08 02:06


以下来自点击打开链接

最小费用最大流

    通过EK,Dinic,ISAP算法可以得到网络流图中的最大流,一个网络流图中最大流的流量max_flow是唯一的,但是达到最大流量max_flow时每条边上的流量分配f是不唯一的。 
    如果给网络流图中的每条边都设置一个费用cost,表示单位流量流经该边时会导致花费cost。那么在这些流量均为max_flow的流量分配f中,存在一个流量总花费最小的最大流方案。 
 min{sum(cost(i, j)*f(i,j) | (i, j)属于方案f中的边, f(i,j)为 边(i,j)上的流量, f为某一个最大流方案}。此即为最小费用最大流

算法思想

    采用贪心的思想,每次找到一条从源点到达汇点的路径,增加流量,且该条路径满足使得增加的流量的花费最小,直到无法找到一条从源点到达汇点的路径,算法结束。 
    由于最大流量有限,每执行一次循环流量都会增加,因此该算法肯定会结束,且同时流量也必定会达到网络的最大流量;同时由于每次都是增加的最小的花费

由归纳法得:当前的最小花费是所有到达当前流量flow时的花费最小值,因此最后的总花费最小。



点击打开链接

题意:n*m地图 n,m<=100,地图中有房子'H'和人'M',每个人能向4个方向移动一个单位,花费1.
每个房子只能住一个人 问把'M'个人移动到'H'个房子中的最小花费?
建图 顶点为:M个人,H个房子,源点S和T 人和房子间连有向边容量为1,费用为曼哈顿距离,源点和人,房子和汇点的容量为1,费用为0
则M个人都要进H个房子的最小费用为:流量为最大流时的最小费用 

#include <iostream>#include <vector>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;typedef long long ll;typedef pair<int,int> ii;const int N=3e2+20;const int inf=2e8;int n,m;struct Edge{int to,vol,cost,next;}e[N*N];int head[N],pre[N],path[N],dist[N];int num;//边void insert(int u,int v,int vol,int cost){e[num].to=v,e[num].vol=vol,e[num].cost=cost;e[num].next=head[u];head[u]=num++;e[num].to=u,e[num].vol=0,e[num].cost=-cost;//反向边 减少容量,则价格也减少e[num].next=head[v];head[v]=num++;} queue<int> q;int inq[N];bool SPFA(int s,int t){while(!q.empty())q.pop();memset(pre,-1,sizeof(pre));memset(dist,0x7f,sizeof(dist));memset(inq,0,sizeof(inq));dist[s]=0;inq[s]=1;q.push(s);while(!q.empty()){int u=q.front();q.pop();inq[u]=0;for(int p=head[u];p!=-1;p=e[p].next){int v=e[p].to;if(e[p].vol>0 &&dist[u]+e[p].cost<dist[v]){dist[v]=dist[u]+e[p].cost;pre[v]=u,path[v]=p;//前一条边和点 if(!inq[v])inq[v]=1,q.push(v);}}}if(pre[t]==-1)return false;return true;}int Min_CostFlow(int s,int t){int cost=0,flow=0;while(SPFA(s,t)){int f=inf;for(int u=t;u!=s;u=pre[u])f=min(f,e[path[u]].vol);flow+=f,cost+=dist[t]*f;for(int u=t;u!=s;u=pre[u]){e[path[u]].vol-=f;e[path[u]^1].vol+=f;//残余网络 }}return cost;}char s[N][N];vector<ii> p1,p2;int cnt;void init(){int off=cnt;for(int i=0;i<p1.size();i++)insert(0,i+1,1,0);for(int j=0;j<p2.size();j++)insert(j+1+off,2*cnt+1,1,0);for(int i=0;i<p1.size();i++){for(int j=0;j<p2.size();j++){int d=abs(p1[i].first-p2[j].first)+abs(p1[i].second-p2[j].second);insert(i+1,j+1+cnt,1,d);}}}int main(){while(cin>>n>>m&&(n+m)){ memset(head,-1,sizeof(head));num=cnt=0;p1.clear(),p2.clear();for(int i=1;i<=n;i++)scanf("%s",s[i]+1);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(s[i][j]=='m')p1.push_back(ii(i,j)),cnt++;if(s[i][j]=='H')p2.push_back(ii(i,j));}}init();int ans=Min_CostFlow(0,2*cnt+1);cout<<ans<<endl;} return 0;}


原创粉丝点击