zoukankan      html  css  js  c++  java
  • 网络流之最小费最大流

    网络流之最小费最大流

    例题

    题目: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
    ",ans);
    	}
    }
    
  • 相关阅读:
    设计模式总结
    字符编码小结
    搞定java.io
    将代码托管到GitHub上
    linuxlinux 路由表设置 之 route 指令详解 路由表设置 之 route 指令详解
    linux子系统的初始化_subsys_initcall()
    Linux系统目录结构介绍
    EtherType :以太网类型字段及值
    socket编程原理
    linux下的网络接口和网络桥接
  • 原文地址:https://www.cnblogs.com/whitelily/p/14034765.html
Copyright © 2011-2022 走看看