网络流相关知识参考: http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html

出处:優YoU http://blog.csdn.net/lyy289065406/article/details/6732762

大致题意:

给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致。man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man。现在要求所有的man都入住house,求最小费用。

解题思路:

费用流问题。

构图:

       把man作为一个顶点集合U,house作为另一个顶点集合V,把U中所有点到V中所有点连线,费用cost[u][v]为abs(△x)+abs(△y),反向弧费用cost[v][u]= -cost[u][v],容量cap[u][v]=1,构成一个多源多汇的二分图。

由于每一个多源多汇的网络流都必有一个与之对应的单源单汇的网络流,为了便于解题,由此构造一个超级源s和超级汇t,超级源s与U中所有点相连,费用cost[s][u]=0(这是显然的),容量cap[s][u]=1;V中所有点与超级汇t相连,费用cost[v][t]=0(这是显然的),容量cap[t][v]=1。

至于其他不连通的点,费用与容量均为0。容量为0的边,可以理解为饱和边,不再连通。而上述的所有边之所以容量初始化为1,是因为每间house只允许入住1个man。而与超级源(汇)相连的边的费用之所以为0,是为了现在所构造的单源单汇网络流最终所求的最小费用等于原来的多源多汇网络流的最小费用。

求解:

接下来的解题方法有关“最小费用最大流”,请未知的同学先去看看相关文献。

       其实题目所求的最小费用,就是最短距离。用spfa算法求上述二分图G的最短路径,该最短路径就是图G的所有增广链中费用最小的一条。比较该增广链上所有边的容量,最小的容量就是“可分配的最大流MaxFlow”。

       再者就是利用MaxFlow对增广链上的各条边的容量进行调整,正向弧容量减去MaxFlow,反向弧容量加上MaxFlow。然后该条增广链上各条边的费用分别乘以MaxFlow之和,就是第一个man到达合适的house所花费的最小费用。而图G经过调整,变成图G1。

       针对图G1再次使用spfa算法,找到第二条增广链.....重复上述算法,直到无法找到增广链为止,则得到的费用和就是所求。

       此种解题方法是先计算最小费用,然后再在保证费用最小的情况下,增大流量,最终达到求解目的。理论上,对于有n个man的图,可以找到n条增广链,即重复迭代spfa算法n次。若超过n次,则说明该图存在负权环,无解。但本题并无输出“无解”的要求,故可认为测试数据中不存在此类数据,因此在循环spfa算法时,不必计算次数,用while()足矣。

最后要注意的是:

       Discuss上很多人说用了栈空间定义的数组,提交会RE或TLE,数组开大之后才能AC,因此便怪罪于测试数据有误。

       其实不然。真正的原因是,题目所提及的N与M纯粹是地图的行数和列数,与man或house的个数无关,而我看了他们的代码,有部分同学却误以为N就是man的个数,导致出现RE。

       因此在此强调一下,题目的N不等于man的个数,建议大家先对地图的man个数进行数数,得到man的个数,然后再开堆空间(new函数);而非要开栈空间的同学也未尝不可,由于N与M的值均<=100,且man与house的个数一致,则认为man的个数上限为100*100/2=5000。

//Memory Time
//612K 63MS #include<iostream>
#include<memory.h>
#include<cmath>
#include<queue>
using namespace std; struct coordinate
{
int x,y;
}; class solve
{
public:
solve(int row,int col):R(row),C(col)
{
MinCost=0;
n=0; Input();
StructureBinaryMap(); pre=new int[2*n+2];
memset(pre,0,sizeof(int)*(2*n+2));
dist=new int[2*n+2];
vist=new bool[2*n+2]; while(spfa())
AddMaxFlow();
}
~solve()
{
cout<<MinCost<<endl; delete[] m;
delete[] H;
delete[] dist;
delete[] vist; for(int i=0;i<R;i++)
delete[] InMap[i]; for(int j=0;j<2*n+2;j++)
{
delete[] cost[j];
delete[] cap[j];
}
} int inf() const{return 0x7FFFFFFF;}
int min(int a,int b) {return a<b?a:b;} void Input(void);
void StructureBinaryMap(void); //构造二分图
bool spfa(void); //搜索从超级源到超级汇的最短路(即最小费用)的增广链
void AddMaxFlow(void); //增广链调整(曾流),计算最小费用 protected:
int R,C; //地图尺寸R*C ,
int n; //the number of man or Houses
int s,t; //s:超级源编号,t:超级汇编号
int MinCost; //最小花费 char** InMap; //输入的地图
coordinate* m; //记录所有man的坐标
coordinate* H; //记录所有House的坐标
int* pre; //最小费用流路径上,结点i的前驱结点为pre[i] int** cost; //两点间费用,其中超级源为0,1~n为man,n+1~2n为house,2n+1为超级汇
int** cap; //两点间容量,其中超级源为0,1~n为man,n+1~2n为house,2n+1为超级汇
int* dist; //超级源到各点的最短距离
bool* vist; //标记各点是否在队列
}; void solve::Input(void)
{
int i,j; InMap=new char*[R];
for(i=0;i<R;i++)
{
InMap[i]=new char[C];
for(j=0;j<C;j++)
{
cin>>InMap[i][j]; if(InMap[i][j]=='m') //检查'm'
n++; //得到man or house的数量
}
}
return;
} void solve::StructureBinaryMap(void)
{
int i,j;
int pm=0,pH=0; m=new coordinate[n+1];
H=new coordinate[n+1]; /*记录各个man与house的坐标*/ for(i=0;i<R;i++)
for(j=0;j<C;j++)
if(InMap[i][j]=='m')
{
m[++pm].x=i;
m[pm].y=j;
}
else if(InMap[i][j]=='H')
{
H[++pH].x=i;
H[pH].y=j;
} /*建立存储空间*/ cost=new int*[2*n+2];
cap=new int*[2*n+2];
for(i=0;i<2*n+2;i++)
{
cost[i]=new int[2*n+2];
cap[i]=new int[2*n+2]; memset(cost[i],0,sizeof(int)*(2*n+2)); //所有路径费用默认为0
memset(cap[i],0,sizeof(int)*(2*n+2)); //所有路径容量默认为0(饱和,不连通)
} /*初始化超级源s到各个man的容量*/ s=0;
for(i=1;i<=n;i++)
cap[s][i]=1; //容量默认为1 /*初始化各个man到house的距离(费用)及容量*/ for(i=1;i<=n;i++)
for(j=n+1;j<=2*n;j++)
{
cost[i][j]=abs(m[i].x-H[j-n].x)+abs(m[i].y-H[j-n].y); //man到house的费用为abs(△x)+abs(△y)
cost[j][i]=-cost[i][j]; //注意顺便构造负权边
cap[i][j]=1;
} /*初始化各个house到超级汇t的容量*/ t=2*n+1;
for(j=n+1;j<t;j++)
cap[j][t]=1; //容量默认为1 return;
} bool solve::spfa(void)
{
dist[s]=0;
for(int i=1;i<2*n+2;i++) //注意这里不能用memset(),memset是对字节为单位进行赋值
dist[i]=inf(); //若非置0,memset对char、bool以外的类型都会赋一个与期望完全不同的数值 memset(vist,false,sizeof(bool)*(2*n+2));
vist[s]=true; queue<int>q;
q.push(s); while(!q.empty())
{
int u=q.front(); //获取队头元素
for(int v=0;v<=t;v++)
{
if(cap[u][v] && dist[v]>dist[u]+cost[u][v]) //u->v容量未饱和,且能够松弛
{
dist[v]=dist[u]+cost[u][v];
pre[v]=u; //记录u的前驱结点 if(!vist[v])
{
q.push(v);
vist[v]=true;
}
}
}
q.pop(); //队头元素出队
vist[u]=false;
} if(dist[t]==inf()) //dist[t]没有被调整,说明已不存在增广链
return false; return true; //找到一条当前费用和最小的增广链
} void solve::AddMaxFlow(void)
{
int MaxFlow=inf(); //可分配最大流
int i; for(i=t;i!=s;i=pre[i]) //可分配最大流 为增广链上的最小容量边的容量
MaxFlow=min(MaxFlow,cap[pre[i]][i]); for(i=t;i!=s;i=pre[i]) //增广链上流量调整(增流)
{
cap[pre[i]][i]-=MaxFlow; //正向弧容量减去可分配最大流
cap[i][pre[i]]+=MaxFlow; //反向弧容量加上可分配最大流
MinCost+=cost[pre[i]][i]*MaxFlow; //最小费用=单位费用*流量
} return;
} int main(void)
{
int row,col;
while(cin>>row>>col && (row+col))
solve poj2195(row,col); return 0;
}

最小费用最大流 POJ2195-Going Home的更多相关文章

  1. POJ2195 Going Home —— 最大权匹配 or 最小费用最大流

    题目链接:https://vjudge.net/problem/POJ-2195 Going Home Time Limit: 1000MS   Memory Limit: 65536K Total ...

  2. POJ2195:Going Home (最小费用最大流)

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26212   Accepted: 13136 题目链接 ...

  3. POJ 2195 Going Home 【最小费用最大流】

    题目链接:http://poj.org/problem?id=2195 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions:2715 ...

  4. [板子]最小费用最大流(Dijkstra增广)

    最小费用最大流板子,没有压行.利用重标号让边权非负,用Dijkstra进行增广,在理论和实际上都比SPFA增广快得多.教程略去.转载请随意. #include <cstdio> #incl ...

  5. bzoj1927最小费用最大流

    其实本来打算做最小费用最大流的题目前先来点模板题的,,,结果看到这道题二话不说(之前打太多了)敲了一个dinic,快写完了发现不对 我当时就这表情→   =_=你TM逗我 刚要删突然感觉dinic的模 ...

  6. ACM/ICPC 之 卡卡的矩阵旅行-最小费用最大流(可做模板)(POJ3422)

    将每个点拆分成原点A与伪点B,A->B有两条单向路(邻接表实现时需要建立一条反向的空边,并保证环路费用和为0),一条残留容量为1,费用为本身的负值(便于计算最短路),另一条残留容量+∞,费用为0 ...

  7. HDU5900 QSC and Master(区间DP + 最小费用最大流)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5900 Description Every school has some legends, ...

  8. P3381 【模板】最小费用最大流

    P3381 [模板]最小费用最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入输出格式 输入格式: 第一行 ...

  9. 【BZOJ-3876】支线剧情 有上下界的网络流(有下界有源有汇最小费用最大流)

    3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 821  Solved: 502[Submit][Status ...

随机推荐

  1. bsgrid

    网址:http://bsgrid.oschina.mopaasapp.com/ var total = gridObj.options.totalRows; jquery必须放在bsgrid的前面 根 ...

  2. JavaWeb学习记录(二十一)——国际化处理

    ¨国际化又称为 i18n:internationalization ¨对于软件中的菜单栏.导航条.错误提示信息,状态信息等这些固定不变的文本信息,可以把它们写在一个properties文件中,并根据不 ...

  3. 多线程问题(JVM重排序)

    public class Test3 { private static boolean ready; private static int Number; private static class R ...

  4. 小巧灵便高效的spx6.0截图三件套(带注册码)

    非常好用截图工具,推荐截图必备,这是三件套完整版本. SPX Instant Screen Capture 是一小巧的屏幕抓图工具,可以抓取选定的区域或整个窗口,可以将抓取的图片发送到剪贴板或 ema ...

  5. java编程之:Unsafe类

    Unsafe类在jdk 源码的多个类中用到,这个类的提供了一些绕开JVM的更底层功能,基于它的实现可以提高效率.但是,它是一把双刃剑:正如它的名字所预示的那样,它是 Unsafe的,它所分配的内存需要 ...

  6. php get set方法深入理解

    在类当中,设计通用的set和get方法,可以简化对属性的读写,这种方法不同于针对于独立的属性的普通的get和set方法,后者针对每个属性,都必须提供一对方法,前者针对所有属性,因此,可以看作是批量定义 ...

  7. 论文笔记之:Multiple Feature Fusion via Weighted Entropy for Visual Tracking

    Multiple Feature Fusion via Weighted Entropy for Visual Tracking ICCV 2015 本文主要考虑的是一个多特征融合的问题.如何有效的进 ...

  8. 此博客记录我的进阶之路(PHP、C、Python、Erlang)

    强大自己!赚钱,装修,娶媳妇!!

  9. OSGi 的核心配置、动态化及问题

    一.OSGi的核心组件Bundle,与java中jar包的差别就是元数据配置:      常用的Bundle元数据定义:     a) Bundle-Activator:定义Activator的实现全 ...

  10. PostgreSQL Hardware Performance Tuning

    Bruce Momjian POSTGRESQL is an object-relational database developed on the Internet by a group of de ...