zoukankan      html  css  js  c++  java
  • poj_2195 最小费用最大流

    题目大意

        一个nxm的地图,地图上的横纵交错成nxm个交叉点,其中有k个交叉点为房间,k个交叉点为k个小人的初始位置。小人可以在地图上沿着水平或垂直方向行走,每走一步的代价为1。求这k个小人分别到达k个不同的房间,所花费的总代价的最小值。

    题目分析

        k个小人走到k个房间节点,走出k条不同的路径,形成一个网络,求出花费最少的k条路径。每个房间只能容纳一个小人,视为小人节点到房间节点的路径上的容量为1,这样就不会出现多个小人挤到同一个房间。那么可以将问题转化为网络流: 
        添加源点s和汇点t,从s出发引出k条边分别到达k个小人,边的容量为1,费用为0;从k个房间节点分别引出一条边到达t,边的容量为1,费用为0;从k个小人节点分别引出k条边达到k个房间节点,边的容量为1,单位费用为小人到房间的最短距离。这样就构造出了一个网络流图,然后求解从源点s到达汇点t的最小费用最大流。

    ps:这种有限制条件(比如容量有限制)的问题可以考虑转化为网络流。

    实现(c++)

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #include<vector>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define INF 1 << 25
    #define MAX_NODE 220
    #define MAX_EDGE_NUM 40005
    #define min(a, b) a<b?a:b
    struct Edge{
    	int to;
    	int vol;
    	int cost;
    	int next;
    };
    Edge gEdges[MAX_EDGE_NUM];
    int gPre[MAX_NODE];
    int gPath[MAX_NODE];
    int gDist[MAX_NODE];
    int gHead[MAX_NODE];
    int gEdgeCount;
    void InsertEdge(int u, int v, int vol, int cost){
    	gEdges[gEdgeCount].to = v;
    	gEdges[gEdgeCount].vol = vol;
    	gEdges[gEdgeCount].cost = cost;
    	gEdges[gEdgeCount].next = gHead[u];
    	gHead[u] = gEdgeCount++;
    
    	gEdges[gEdgeCount].to = u;
    	gEdges[gEdgeCount].vol = 0;
    	gEdges[gEdgeCount].cost = -cost;
    	gEdges[gEdgeCount].next = gHead[v];
    	gHead[v] = gEdgeCount++;
    }
    //spfa算法求最短路(即增广单位费用最小的从源到汇的路径)
    bool Spfa(int s, int t){
    	memset(gDist, 0x7F, sizeof(gDist));
    	memset(gPre, -1, sizeof(gPre));
    	gDist[s] = 0;
    	queue<int>Q;
    	Q.push(s);
    	while (!Q.empty()){
    		int u = Q.front();
    		Q.pop();
    		for (int e = gHead[u]; e != -1; e = gEdges[e].next){
    			int v = gEdges[e].to;
    			if (gEdges[e].vol > 0 && gDist[v] > gDist[u] + gEdges[e].cost){
    				gDist[v] = gDist[u] + gEdges[e].cost;
    				gPre[v] = u;
    				gPath[v] = e;
    				Q.push(v);
    			}
    		}
    	}
    	return gPre[t] != -1;
    }
    
    int MinCostFlow(int s, int t){
    	int cost = 0;
    	int max_flow = 0;
    	int u, v, e;
    	while (Spfa(s, t)){
    		int f = INF;
    		for (u = t; u != s; u = gPre[u]){
    			f = min(f, gEdges[gPath[u]].vol);
    		}
    
    		for (u = t; u != s; u = gPre[u]){
    			e = gPath[u];
    			gEdges[e].vol -= f;
    			gEdges[e^1].vol += f;	//反向边
    		}
    		max_flow += f;
    		cost += f*gDist[t];
    	}
    	return cost;
    }
    
    char gMap[105][105];
    vector<pair<int, int> > gHousVec;
    vector<pair<int, int> > gManVec;
    //建图
    void BuildGraph(){
    	int n = gHousVec.size();
    	// 源点0,连接到每个小人结点,流量为1,单位费用为0
    	for (int u = 1; u <= n; u++){
    		InsertEdge(0, u, 1, 0);
    	}
    	for (int i = 0; i < n; i++){
    		for (int j = 0; j < n; j++){ 
    			//求出小人i到房间j的最短距离
    			int min_dist = abs(gManVec[i].first - gHousVec[j].first) + abs(gManVec[i].second - gHousVec[j].second);
    			//建边,连接小人i和房间j
    			InsertEdge(i + 1, j + n + 1, 1, min_dist);
    		}
    	}
    	//汇点 2*n+1,连接各个房间借点到汇点,流量为1,单位费用为0
    	for (int u = 1; u <= n; u++){
    		InsertEdge(n + u, 2 * n + 1, 1, 0);
    	}
    }
    int main(){
    	int n, m;
    	while (scanf("%d %d", &n, &m) && n && m){
    		char tmp;
    		gHousVec.clear();	//初始化
    		gManVec.clear();
    		memset(gHead, -1, sizeof(gHead)); //图的初始化
    		gEdgeCount = 0;	//图的初始化
    
    		for (int i = 1; i <= n; i++){
    			getchar();
    			for (int j = 1; j <= m; j++){
    				scanf("%c", &tmp);
    				if (tmp == 'H'){
    					gHousVec.push_back(pair<int, int>(i, j));
    				}
    				else if (tmp == 'm'){
    					gManVec.push_back(pair<int, int>(i, j));
    				}
    			}
    		}
    		BuildGraph();  //建图
    		int cost = MinCostFlow(0, 2 * gHousVec.size() + 1); //求解最小费用最大流
    		printf("%d
    ", cost);
    	}
    	return 0;
    }
    
  • 相关阅读:
    四,redis6版本的使用部署
    记录篇-浪潮服务器raid卡
    sudo漏洞解决方案--源码转rpm包(spec文件编写)
    关闭 Chrome 浏览器阅读清单功能
    【转译】如何成为一个数据工程师?
    Python 用最小堆获取大量元素 topk 大个元素
    Python 实现二分查找
    Python 排序算法之堆排序,使用 heapq 实现
    Python 排序算法之归并排序
    Python 排序算法之快速排序
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4890944.html
Copyright © 2011-2022 走看看