poj2195 -最小费用流
来源:互联网 发布:淘宝女靴新款 编辑:程序博客网 时间:2024/04/29 10:20
Going Home
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 21616 Accepted: 10919
Description
On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man.
Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point.
You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point.
You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
Input
There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H's and 'm's on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.
Output
For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.
Sample Input
2 2.mH.5 5HH..m...............mm..H7 8...H.......H.......H....mmmHmmmm...H.......H.......H....0 0
Sample Output
21028
题意:一个n*m的棋盘,H表示房子,m表示人,每个人都要到一个房子里去,走一个格子要花费1美元,问所有人回到房子里总花费
最少是多少;
每一个人去一个房子,不能两个人同时去一个房子,显然可以看成二分图最小权匹配,一个KM算法可以搞定,房子看成X集合人看成
Y集合,集合间每个人与每个房子两两建边,权值为负的两者距离,然后就没有然后了,KM算法搞定
#include <stdio.h>#include <string.h>#include <math.h>#include <stdlib.h>#include <algorithm>#include <iostream>#include <queue>using namespace std;const int maxn=105,inf=0x3f3f3f3f;int g[maxn][maxn];int nx,ny;int linker[maxn],lx[maxn],ly[maxn];int slack[maxn];bool visx[maxn],visy[maxn];struct node{ int i,j;} H[maxn],M[maxn];int solve(int x,int y){ return abs(H[x].i-M[y].i)+abs(H[x].j-M[y].j);}bool dfs(int x){ visx[x]=true; for(int y=0; y<ny; y++) { if(visy[y]) continue; int tmp=lx[x]+ly[y]-g[x][y]; if(tmp==0) { visy[y]=true; if(linker[y]==-1||dfs(linker[y])) { linker[y]=x; return true; } } else if(slack[y]>tmp) slack[y]=tmp; } return false;}int KM(){ memset(linker,-1,sizeof(linker)); memset(ly,0,sizeof(ly)); for(int i=0; i<nx; i++) { lx[i]=-inf; for(int j=0; j<ny; j++) { if(g[i][j]>lx[i]) lx[i]=g[i][j]; } } for(int x=0; x<nx; x++) { for(int i=0; i<ny; i++) slack[i]=inf; while(true) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if(dfs(x))break; int d=inf; for(int i=0; i<ny; i++) { if(!visy[i]&&d>slack[i]) d=slack[i]; } for(int i=0; i<nx; i++) { if(visx[i]) lx[i]-=d; } for(int i=0; i<ny; i++) { if(visy[i]) ly[i]+=d; else slack[i]-=d; } } } int res=0; for(int i=0; i<ny; i++) if(linker[i]!=-1) res+=g[linker[i]][i]; return res;}char str[maxn][maxn];int main(){ int n,m; int tom,toh; while(scanf("%d%d",&n,&m)!=-1) { if(n==0&m==0) break; toh=tom=0; for(int i=0; i<n; i++) { scanf("%s",str[i]); for(int j=0; j<m; j++) { if(str[i][j]=='H') { H[toh].i=i; H[toh++].j=j; } if(str[i][j]=='m') { M[tom].i=i; M[tom++].j=j; } } } ny=tom; nx=toh; for(int i=0; i<toh; i++) { for(int j=0; j<tom; j++) { g[i][j]=-solve(i,j); } } printf("%d\n",-KM()); } return 0;}第二种算法是最小费用最大流,同理X Y 集合房子与人两两建边,流量为1,花费为距离,然后建立源点汇点,源点连接X集合,Y集合连接汇点,流量为1,费用为0,因为从源点到X集合每条边使用过流量就减为0了,Y集到汇点每条边使用
过后流量减为0,也就是说X Y 集合 每个点只能用一次,用过后流量就没有了,每次优先选择花费最小的路径,总话费肯定也是最小
的,最小话费就是我们要的结果了;
--模板大法好--
#include <stdio.h>#include <string.h>#include <math.h>#include <stdlib.h>#include <algorithm>#include <iostream>#include <queue>using namespace std;const int maxn=1e5+5,inf=0x3f3f3f3f;struct Edge{ int u,to,next,cap,cost;}edge[maxn];int tot,head[maxn];int vis[maxn],dis[maxn],pre[maxn];char str[105][105];struct node{ int i,j;}H[maxn],M[maxn];void init(){ tot=0; memset(head,-1,sizeof(head));}void addedge(int u,int v,int cap,int cost){ edge[tot].u=u; edge[tot].to=v; edge[tot].next=head[u]; edge[tot].cap=cap; edge[tot].cost=cost; head[u]=tot++; edge[tot].u=v; edge[tot].to=u; edge[tot].cap=0; edge[tot].cost=-cost;///花费必须是负值 edge[tot].next=head[v]; head[v]=tot++;}bool spfa(int start,int end){ int u,v; queue<int>que; for(int i=0;i<end+2;i++) { pre[i]=-1; vis[i]=0; dis[i]=inf; } vis[start]=1; dis[start]=0; que.push(start); while(!que.empty()) { u=que.front(); que.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].next) { cout<<edge[i].cost<<endl; if(edge[i].cap)///有流量才有最短路啊 { v=edge[i].to; if(dis[v]>dis[u]+edge[i].cost) { dis[v]=dis[u]+edge[i].cost; pre[v]=i; if(!vis[v]) { vis[v]=1; que.push(v); } } } } } return dis[end]!=inf;}int mcMF(int start,int end){ int ans=0; //int flow_sum=0; while(spfa(start,end)) { /* flow=inf; for(int i=pre[end];i!=-1;i=pre[edge[i].u]) { if(edge[i].cap<flow) flow=edge[i].cap; }*/ for(int i=pre[end];i!=-1;i=pre[edge[i].u]) { edge[i].cap-=1;///流量都是1 减1就好了,所以上面求最小流量的过程就省去了 edge[i^1].cap+=1; } ans+=dis[end]; } return ans;}int solve(int x,int y){ return abs(H[x].i-M[y].i)+abs(H[x].j-M[y].j);}int main(){ int n,m; int tom,toh; int S,T; while(scanf("%d%d",&n,&m)!=-1) { if(n==0&m==0) break; toh=tom=0; S=20004; T=20005; int k=10001; ///100*100 的矩阵,所以设置k=10001 init(); for(int i=0;i<n;i++) { scanf("%s",str[i]); for(int j=0;j<m;j++) { if(str[i][j]=='H') { H[toh].i=i; H[toh].j=j; addedge(S,toh,1,0); toh++; } if(str[i][j]=='m') { M[tom].i=i; M[tom].j=j; addedge(tom+k,T,1,0); tom++; } } } for(int i=0;i<toh;i++) { for(int j=0;j<tom;j++) { addedge(i,j+k,1,solve(i,j)); } } printf("%d\n",mcMF(S,T)); } return 0;}
0 0
- poj2195 -最小费用流
- 最小费用最大流--poj2195
- POJ2195(最小费用最大流)
- POJ2195 Going Home 最小费用最大流
- poj2195 Going Home,最小费用最大流
- poj2195--Going Home(最小费用最大流)
- poj2195 Going Home 最小费用最大流
- poj2195 spfa 最小费用最大流
- poj2195 going home最小费用流
- POJ2195-Going Home(最小费用流)
- POJ2195 Going Home 【最小费用流】+【二分图最佳匹配】
- POJ2195 Going Home(SPFA最小费用最大流)
- poj2195(二分图最大匹配,最小费用流)
- poj2195 Going Home(最大费用最小流)
- POJ2195 Going Home(最小费用最大流mcmf)
- POJ2195-Going Home(最小费用最大流)
- poj2195——Going Home(最小费用最大流)
- 【POJ2195】Going Home-最小费用最大流模板题
- Eclipse配置安装Tomcat插件教程
- UIView动画(过渡效果)的学习笔记
- 在一台linux机器上启动两个mysql实例
- 关于C++ 容器的swap操作
- git忽略文件
- poj2195 -最小费用流
- 八大排序算法
- 映射表原理分析与总结
- 远程设备运维云平台软件与常规组态软件的区别(V1.1)?
- Docker Registry v2的搭建后任何用随意pull和push的问题
- s3c2440 RTC(实时时钟) 驱动移植
- 小米手环2来电不震动,来电不提醒怎么办
- android仿微信底部导航栏+viewPager+自定义view
- hdu-4027-线段树+暴力