Going Home
题意: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 ;
- }
随机推荐
- 【arc074e】RGB Sequence(动态规划)
[arc074e]RGB Sequence(动态规划) 题面 atcoder 洛谷 翻译见洛谷 题解 直接考虑暴力\(dp\),设\(f[i][j][k][l]\)表示当前考虑到第\(i\)位,最后一 ...
- 洛谷 P1344 [USACO4.4]追查坏牛奶Pollutant Control 解题报告
P1344 [USACO4.4]追查坏牛奶Pollutant Control 题目描述 你第一天接手三鹿牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批有三聚氰胺的牛奶.很不幸,你发现这件事的时候 ...
- suoi44 核能显示屏 (cdq分治)
首先二维树状数组肯定开不下 仿照二维树状数组的做法,如果有差分数组$d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]$,那么就有: $$sum[x][y] ...
- 结合NTLM中继和Kerberos委派攻击AD
0x00 前言 在上个月我深入演讲了无约束委派之后,本文将讨论一种不同类型的Kerberos委派:基于资源的约束委派.本文的内容基于Elad Shamir的Kerberos研究,并结合我自己的NTLM ...
- Libre 6005 「网络流 24 题」最长递增子序列 / Luogu 2766 最长递增子序列问题(网络流,最大流)
Libre 6005 「网络流 24 题」最长递增子序列 / Luogu 2766 最长递增子序列问题(网络流,最大流) Description 问题描述: 给定正整数序列x1,...,xn . (1 ...
- AC自动机——多个kmp匹配
(并不能自动AC) 介绍: Aho-Corasick automaton,最经典的处理多个模式串的匹配问题. 是kmp和字典树的结合. 精髓与灵魂: ①利用trie处理多个模式串 ②引入fail指针. ...
- OpenStack 存储服务 Cinder存储节点部署NFS(十七)
Cinder存储节点部署 1.安装软件包 yum install -y nfs-utils rpcbind 提示:早期版本安装portmap nfs-utils :包括基本的NFS命令与监控程序 rp ...
- python 爬虫 scrapy1_官网教程
Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...
- 鸟哥的Linux私房菜——第九章
视频链接,推荐看B站 土豆网:http://www.tudou.com/programs/view/XmMDbjJHJC8 B站:http://www.bilibili.com/video/av966 ...
- angularJs的继承
为什么要继承,本来是后端的概念,但是同样适用于前端开发.继承,无疑是将通用的东西抽取出来. 下面介绍的是angular的伪继承,就是说是通过继承scope这个变量来实现的.代码很简单,一行代码就可以. ...