网络流之最小费最大流

网络流之最小费最大流

例题

题目:n个人,m个房,要求每个人都回房间且路程和最短,每个人都回房间就是最大流为n,同时要求路程和最短就是还要要求费用最小了。

相较于最大流,要求跑最大流的同时要求费用最低,那么我们便不能够,将dfs的路径全部加入答案,因为里面费用可能会花的更多,所以我们只能降低效率,每次只增广一条最短路,用spfa找最短路,并记录路径后更新最大流于费用即可。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
#define ll long long
const ll inf=1e18;
int st,fi,n,m,tot,head[1000007],vis[1000007],pe[1000007],pn[1000007];
ll fw,dis[1000007],ans;
char s[107][107];
vector<pair<int,int> >H,M;
struct madoka{
	int to;
	int next;
	ll w;
	ll z;
}e[1000007];
void add(int u,int v,ll w,ll z){
	e[++tot].to=v;
	e[tot].next=head[u];
	e[tot].w=w;
	e[tot].z=z;
	head[u]=tot;
	e[++tot].to=u;
	e[tot].next=head[v];
	e[tot].w=0;
	e[tot].z=-z;
	head[v]=tot;
}
bool spfa(){
	queue<int>sa;
	for(int i=1;i<=fi;i++){
		dis[i]=inf;
		vis[i]=0;
	}
	sa.push(st);
	dis[st]=0;
	vis[st]=1;
	while(!sa.empty()){
		int p=sa.front();
		sa.pop();
		vis[p]=0;
		for(int i=head[p];i!=0;i=e[i].next){
			int to=e[i].to;
			if(e[i].w&&dis[p]+e[i].z<dis[to]){
				dis[to]=dis[p]+e[i].z;
				pn[to]=p;
				pe[to]=i;
				if(vis[to]==0){
					vis[to]=1;
					sa.push(to);
				}
			}
		}
	}
	if(dis[fi]==inf){
		return 0;
	}
	return 1;
}
ll go(int p,ll now){
	if(p==st)return now;
	ll lin=go(pn[p],min(now,e[pe[p]].w));
	e[pe[p]].w-=lin;
	e[pe[p]^1].w+=lin;
	return lin;
}
void dinic(){
	fw=0;
	ans=0;
	while(spfa()){
		ll now=go(fi,inf);
		fw+=now;
		ans+=dis[fi]*now;
	}
}
void init(){
	tot=1;
	memset(head,0,sizeof(head));
	M.clear();
	H.clear();
}
int main(){
	while(1){
		init();
		scanf("%d%d",&n,&m);
		if(n==0&&m==0)break;
		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'){
					M.push_back({i,j});
				}
				if(s[i][j]=='H'){
					H.push_back({i,j});
				}
			}
		}
		st=M.size()+H.size()+1;
		fi=M.size()+H.size()+2;
		for(int i=0;i<M.size();i++){
			add(st,i+1,1,0);
		}
		for(int i=0;i<H.size();i++){
			add(M.size()+i+1,fi,1,0);
		}
		for(int i=0;i<M.size();i++){
			for(int j=0;j<H.size();j++){
				add(i+1,M.size()+j+1,1,abs(M[i].first-H[j].first)+abs(M[i].second-H[j].second));
			}
		}
		dinic();
		printf("%lld\n",ans);
	}
}
posted @ 2020-11-25 11:03  ccsu_madoka  阅读(131)  评论(0编辑  收藏  举报