题意: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. 【字符串算法2】浅谈Manacher算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  字符串算法2:Manacher算法 问题:给出字符串S(限制见后)求出最 ...

  2. wps相关问题

    1 总汇 1.1 关闭wps中“我的wps”选项卡 我记得之前的WPS都是可以设置的不启动"我的WPS"的,但是最新版本中好象没有发现这个设置,反正小编是没找到,但是这并不影响我们 ...

  3. Python远程连接模块-Telnet

    Python远程连接模块-Telnet 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 虽然现在主流的python版本还是2.7,相信2020年python程序员都会偏向Python ...

  4. 【转载】SQL注入原理讲解

    这几篇文章讲的都很不错,我看了大概清除了sql注入是怎么一回事,打算细细研究一下这个知识,另写一篇博客: 原文地址:http://www.cnblogs.com/rush/archive/2011/1 ...

  5. JVM总结(一):概述--JVM对象探秘

    这一节我们来讨论一下JVM对象建立过程. JVM对象探秘 对象的建立 对象的内存布局 对象的访问定位 JVM对象探秘 对象的建立 对象的建立过程   图一:对象建立过程 1.类加载检查. 当JVM检测 ...

  6. webpack:代码分割与按需加载

    代码分割就是我们根据实际业务需求将代码进行分割,然后在合适的时候在将其加载进入文档中. 代码中总有些东西我们希望拆分开来,比如: 使用概率较低的模块,希望后期使用的时候异步加载 框架代码,希望能利用浏 ...

  7. 数学:二次剩余与n次剩余

    二次剩余求的是这个东西 如果给定x,再给定若干个大的质数p,如果结果a相同,那么x是完全平方数? 给出别人的二次剩余的代码: /*poj 1808 题意: 判断平方剩余,即判断(x^2)%p=a是否有 ...

  8. BFS搜索算法应用_Codevs 1004 四子连棋

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <algorithm> #include <cs ...

  9. xmlhttprequest upload

    html5 带进度上传 function fileSelected() { var file = document.getElementById('fileToUpload').files[0]; i ...

  10. git使用常用命令

    第一部分:个人整理部分(读<Git教程By廖雪峰.pdf>笔记) /* 配置全局参数 */git config --global user.name "username" ...