zoukankan      html  css  js  c++  java
  • POJ-2195 Going Home(费用流)

    题意:有一张地图,m表示人,h表示房子,每个房子只能进一个人,房子数等于人数。为每个人分配一个房子,求每个人到每个房子的最短距离之和。

    分析:最小费用流。从源点向每个人连一条容量为1的边,从每个人向每个房子连一条容量为1的边,费用为汉密尔顿距离,再从每个房子向汇点连一条容量为1,费用为0的边。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 10005, M = 4 * 10005;
    const int inf = 0x3f3f3f3f;
    int h[N], e[M], ne[M], w[M], cost[M], idx;
    int d[N], incf[N], pre[N];
    bool st[N];
    
    int s, t, maxflow, res;
    
    char g[105][105];
    
    void add(int a, int b, int z, int c)
    {
    	e[idx] = b, w[idx] = z, cost[idx] = c, ne[idx] = h[a], h[a] = idx++;
    	e[idx] = a, w[idx] = 0, cost[idx] = -c, ne[idx] = h[b], h[b] = idx++;
    }
    
    bool spfa()
    {
    	queue<int> q;
    	q.push(s);
    	memset(d, 0x3f, sizeof d);
    	memset(st, 0, sizeof st);
    	d[s] = 0, st[s] = true;
    	incf[s] = 1 << 30;
    	while (q.size())
    	{
    		int u = q.front();
    		q.pop();
    		st[u] = false;
    		for (int i = h[u]; i != -1; i = ne[i])
    		{
    			int j = e[i];
    			if (!w[i]) continue;
    			if (d[j] > d[u] + cost[i])
    			{
    				d[j] = d[u] + cost[i];
    				incf[j] = min(incf[u], w[i]);
    				pre[j] = i;
    				if (!st[j])
    				{
    					st[j] = true;
    					q.push(j);
    				}
    			}
    		}
    	}
    	if (d[t] == 0x3f3f3f3f) return false;
    	return true;
    }
    
    void update()
    {
    	int u = t;
    	while (u != s)
    	{
    		int i = pre[u];
    		w[i] -= incf[t];
    		w[i ^ 1] += incf[t];
    		u = e[i ^ 1];
    	}
    	maxflow += incf[t];
    	res += d[t] * incf[t];
    }
    
    
    int n, m;
    int num(int i, int j)
    {
    	return i * m + j;
    }
    
    int get(int num1, int num2)
    {
    	int x1 = num1 % m, y1 = num1 / m;
    	int x2 = num2 % m, y2 = num2 / m;
    
    	int dist = abs(x1 - x2) + abs(y1 - y2);
    	return dist;
    }
    
    int main()
    {	
    	while (scanf("%d%d", &n, &m) != EOF)
    	{
    		if (n == 0 && m == 0) break;
    		memset(h, -1, sizeof h), idx = 0;
    		res = 0, maxflow = 0;
    		scanf("%d%d", &n, &m);
    
    		for (int i = 0; i < n; ++i) scanf("%s", g + i);
    
    		s = n * m + 1, t = n * m + 2;
    
    		vector<int> p;
    		vector<int> hou;
    		//源点向人连边
    		for (int i = 0; i < n; ++i)
    			for (int j = 0; j < m; ++j)
    			{
    				if (g[i][j] == 'm')
    				{
    					p.push_back(num(i, j));
    					add(s, num(i, j), 1, 0);
    				}
    				if (g[i][j] == 'H')
    				{
    					hou.push_back(num(i, j));
    				}
    			}
    
    		//人向房子连边
    		for (int i = 0; i < p.size(); ++i)
    		{
    			for (int j = 0; j < hou.size(); ++j)
    			{
    				add(p[i], hou[j], 1, get(p[i], hou[j]));
    			}
    		}
    
    		//房子向汇点连边
    		for (int i = 0; i < hou.size(); ++i)
    		{
    			add(hou[i], t, 1, 0);
    		}
    
    		while (spfa()) update();
    
    		printf("%d
    ", res);
    	}
    	
    
    	return 0;
    }
    
  • 相关阅读:
    JS正则表达式大全(整理详细且实用)
    你真的会使用XMLHttpRequest吗?
    pyCharm最新激活码(2018激活码)
    Hibernate 中配置属性详解(hibernate.properties)
    c3p0详细配置
    使用Git上传本地项目到http://git.oschina.net
    深入理解Java:注解(Annotation)自定义注解入门
    SpringMVC文件上传与下载
    C语言开发系列-二进制
    C开发系列-include
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13331543.html
Copyright © 2011-2022 走看看