题意:n个人,进n个房子,每走一格花费1美元,每个房子只能进一人,求所有人进房子的最小花费。   就是推箱子 箱子最短行走距离

这题无法用bfs做 !

用最小花费最大流

通过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为某一个最大流方案}。此即为最小费用最大流

建图:

超级源点到所有人   每个人到每个房子均算出花费   所有房子到超级汇点  所有的边均为1     花费除了人到房子均为0

可当作最小花费最大流模板:

#include <cstdio>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <algorithm>
#define MAXN 200+10
#define MAXM 80000+100
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
int from, to, cap, flow, cost, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int pre[MAXN], dist[MAXN];
bool vis[MAXN];
int N, M;
int cost, flow;
int sink, source;//超级源点 超级汇点
void init()
{
edgenum = ;
memset(head, -, sizeof(head));
}
void addEdge(int u, int v, int w, int c)
{
Edge E1 = {u, v, w, , c, head[u]};
edge[edgenum] = E1;
head[u] = edgenum++;
Edge E2 = {v, u, , , -c, head[v]};
edge[edgenum] = E2;
head[v] = edgenum++;
}
int dis(int x1, int y1, int x2, int y2)
{
return abs(x1 - x2) + abs(y1 - y2);
}
struct Node
{
int x, y;
};
Node m[], H[];//存储字符坐标 bool SPFA(int s, int t)//寻找花销最少的路径
{
queue<int> Q;
memset(dist, INF, sizeof(dist));
memset(vis, false, sizeof(vis));
memset(pre, -, sizeof(pre));
dist[s] = ;
vis[s] = true;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = false;
for(int i = head[u]; i != -; i = edge[i].next)
{
Edge E = edge[i];
if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow)//可以松弛 且 没有满流
{
dist[E.to] = dist[u] + E.cost;
pre[E.to] = i;//记录前驱边 的编号
if(!vis[E.to])
{
vis[E.to] = true;
Q.push(E.to);
}
}
}
}
return pre[t] != -;//可达返回true
}
void MCMF(int s, int t)
{
flow = ;//总流量
cost = ;//总费用 while(SPFA(s, t))//每次寻找花销最小的路径
{
int Min = INF;
//通过反向弧 在源点到汇点的最少花费路径 找最小增广流
for(int i = pre[t]; i != -; i = pre[edge[i^].to])
{
Edge E = edge[i];
Min = min(Min, E.cap - E.flow);
}
//增广
for(int i = pre[t]; i != -; i = pre[edge[i^].to])
{
edge[i].flow += Min;
edge[i^].flow -= Min;
cost += edge[i].cost * Min;//增广流的花销
}
flow += Min;//流量累加
}
}
int main()
{
int m_cnt;//m字符计数器
int H_cnt;//H字符计数器 while(scanf("%d%d", &N, &M), N||M)
{
init(); m_cnt = H_cnt = ;
char str[][];
for(int i = ; i < N; i++)
{
scanf("%s", str[i]);
for(int j = ; j < M; j++)
{
if(str[i][j] == 'm')
{
++m_cnt;
m[m_cnt].x = i;
m[m_cnt].y = j;
}
if(str[i][j] == 'H')
{
++H_cnt;
H[H_cnt].x = i;
H[H_cnt].y = j;
}
}
}
int k = m_cnt;//人数 或者 房子数
sink = ;
source = *k+;
for(int i = ; i <= k; i++)
{
addEdge(sink, i, , );
addEdge(i + k, source, , );
for(int j = ; j <= k; j++)
{
int d = dis(H[i].x, H[i].y, m[j].x, m[j].y);
addEdge(i, j + k, , d);
}
} MCMF(sink, source);
printf("%d\n", cost);
}
return ;
}

随机推荐

  1. [COGS 2551] 新型武器

    图片加载可能有点慢,请跳过题面先看题解,谢谢 这个题好多解法啊... 可以主席树,可以按深度将操作排序离线做 我这里是动态开点线段树,对每一个深度种一棵线段树,下标是节点的\(dfs\)序 然后这个做 ...

  2. JS中的继承链

    我们首先定义一个构造函数Person,然后定义一个对象p,JS代码如下: function Person(name) { this.name = name; } var p = new Person( ...

  3. [Spring] 学习Spring Boot之一:基本使用及简析

    一.简介 使用 Spring Boot 目的主要是用来简化 Spring 应用的搭建及开发过程,因为使用 Spring 及 SpringMVC 框架时需要手动配置的地方非常多(各种包之间的依赖.各种配 ...

  4. 把jQuery的类、插件封装成seajs的模块的方法

    这篇文章主要介绍了把jQuery的类.插件封装成seajs的模块的方法,需要的朋友可以参考下 注:本文使用的seajs版本是2.1.1 一.把Jquery封装成seajs的模块 define(func ...

  5. [转载]必须Mark!最佳HTML5应用开发工具推荐

    http://www.csdn.net/article/2014-04-25/2819503-10-html5-tools-worth-checking-out/2 摘要:HTML5自诞生以来,作为新 ...

  6. 分布式文件系统 之 数据块(Block)

    众所周知,HDFS中以数据块(block)为单位进行存储管理.本文简单介绍一下HDFS中数据块(block)的概念,以及众多分布式存储系统(不止是HDFS)使用block作为存储管理基本单位的意义. ...

  7. ARC 之内存转换

    CHENYILONG Blog ARC 之内存转换 技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http://weibo.com/luohanchenyilo ...

  8. linux驱动---等待队列、工作队列、Tasklets【转】

    转自:https://blog.csdn.net/ezimu/article/details/54851148 概述: 等待队列.工作队列.Tasklet都是linux驱动很重要的API,下面主要从用 ...

  9. Git 使用规范流程【转】

    转自:http://www.ruanyifeng.com/blog/2015/08/git-use-process.html 作者: 阮一峰 日期: 2015年8月 5日 团队开发中,遵循一个合理.清 ...

  10. mac安装sentry

    最近需要一个日志监视系统所以选择了sentry. 安装docker https://download.docker.com/mac/stable/Docker.dmg 登录 安装完了打开 会提示登录输 ...