您的位置:首页 > 编程语言 > Go语言

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

2017-05-23 12:17 447 查看
以下来自点击打开链接


最小费用最大流

    通过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
,pre
,path
,dist
;
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
;
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

;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: