POJ 2195 Going Home (最小费用最大流)
2016-12-12 16:57
501 查看
题目链接
第一次写最小费用最大流
最小费用最大流相当于最短路和最大流的结合,建立了残量图后,费用作为距离
然后bfs遍历源点到汇点的最小费用,用数组记录遍历路径,而后通过最大流的做法
对残量图进行更新,寻找路径中的最小流量得到的就是最小费用最大流。
题目大意:图中有若干个m和H,每个m都要回到一个H,问最少走多少步
这里可以把走的步数定位费用
于是可以建图
源点 链接 人 流量为1 费用为0
人 链接 家 流量为 1 费用为bfs得到的最小步数
家 链接 汇点 流量为 1 费用为 0
跑一遍最小费用最大流就可以得到答案啦
第一次写最小费用最大流
最小费用最大流相当于最短路和最大流的结合,建立了残量图后,费用作为距离
然后bfs遍历源点到汇点的最小费用,用数组记录遍历路径,而后通过最大流的做法
对残量图进行更新,寻找路径中的最小流量得到的就是最小费用最大流。
题目大意:图中有若干个m和H,每个m都要回到一个H,问最少走多少步
这里可以把走的步数定位费用
于是可以建图
源点 链接 人 流量为1 费用为0
人 链接 家 流量为 1 费用为bfs得到的最小步数
家 链接 汇点 流量为 1 费用为 0
跑一遍最小费用最大流就可以得到答案啦
#include<stdio.h> #include<queue> #include<string.h> #include<vector> using namespace std; #define MAXN 1005 #define INF 2000000000 int source,sink; //源点 汇点 struct tree { int from,to,flow,worth,next; //结点,流量,费用,链表 tree(){} tree(int fr,int ro,int fl,int wo,int ne) { from=fr,to=ro,flow=fl,worth=wo,next=ne; } }e[MAXN*MAXN]; int g[MAXN]; // 建立链表 int num; //边数 void init() //初始化 { memset(g,0,sizeof(g)); num=1; } void addtree(int from,int to,int flow,int worth) //建图 { e[++num]=tree(from,to,flow,worth,g[from]); g[from]=num; e[++num]=tree(to,from,0,-worth,g[to]); //反向弧 g[to]=num; } bool visque[MAXN]; //查看是否入队 int dis[MAXN]; //最小距离 int pre[MAXN],prx[MAXN]; //记录路线用于更新残量图 queue<int>q; int bfs() //寻找最短路 { while(!q.empty()) q.pop(); //初始化队列 for(int i=0;i<=MAXN;i++) dis[i]=INF; //初始化距离 q.push(source); //源点入队 dis[source]=0; visque[source]=true; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=g[u];i;i=e[i].next) { if(e[i].flow>0&&dis[u]+e[i].worth<dis[e[i].to]) //更新最短路 { dis[e[i].to]=dis[u]+e[i].worth; pre[e[i].to]=u; prx[e[i].to]=i; if(!visque[e[i].to]) { visque[e[i].to]=true; q.push(e[i].to); } } } visque[u]=false; //前面已经让u出队了所以这里要写一下 } return dis[sink]!=INF; //判断是否可以到达汇点 } int dfs() { int u=sink; int ans=INF; while(u!=source) //找当前路中的最小流量 { if(e[prx[u]].flow<ans) ans=e[prx[u]].flow; u=pre[u]; } u=sink; while(u!=source) //更新残量图 { e[prx[u]].flow-=ans; e[prx[u]^1].flow+=ans; u=pre[u]; } return ans*dis[sink]; } int solve() { int cur=0; int ans=0; while(bfs()) { cur+=dfs(); if(cur>ans) ans=cur; } return ans; } char map[MAXN][MAXN]; int mapnum[MAXN][MAXN]; int n,m; struct Point { int x,y,w; Point(){} Point(int xx,int yy,int ww) { x=xx,y=yy,w=ww; } }; int vis[MAXN][MAXN]; int tur[4][2]={1,0,-1,0,0,1,0,-1}; void bfs_m(Point s) { queue<Point> v; v.push(s); memset(vis,0,sizeof(vis)); vis[s.x][s.y]=1; while(!v.empty()) { Point u=v.front(); v.pop(); if(map[u.x][u.y]=='H') addtree(mapnum[s.x][s.y],mapnum[u.x][u.y],1,u.w); for(int i=0;i<4;i++) { Point pp=u; pp.x+=tur[i][0]; pp.y+=tur[i][1]; if(pp.x<0||pp.y<0||pp.x>=n||pp.y>=m||vis[pp.x][pp.y])continue; vis[pp.x][pp.y]=1; pp.w++; v.push(pp); } } } int main() { while(scanf("%d%d",&n,&m)==2,n+m) { init(); sink=1000,source=1; int cout=2; for(int i=0;i<n;i++) { scanf("%s",map[i]); for(int j=0;j<m;j++) { if(map[i][j]=='.') continue; mapnum[i][j]=cout++; //给点编号利于建图 if(map[i][j]=='m') addtree(source,mapnum[i][j],1,0); else addtree(mapnum[i][j],sink,1,0); } } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { if(map[i][j]=='m') bfs_m(Point(i,j,0)); //寻找每一个人对应所有家的最短路 } } printf("%d\n",solve()); } }
相关文章推荐
- POJ 2195 & HDU 1533 Going Home(最小费用最大流)
- POJ 2195 Going Home (最佳完美匹配, 最小费用最大流)
- POJ 2195 - Going Home 更新最小费用最大流模板..整合成结构体...
- poj - 2195 - Going Home(最小费用最大流)
- POJ-2195 Going Home(最小费用最大流)
- POJ 2195 Going Home 最小费用最大流
- POJ 2195 && HDU 1533 Going Home(最小费用最大流-mcmf)
- poj 2195 Going Home(最小费用最大流)
- POJ 2195 Going Home【最小费用最大流】
- poj-2195-Going Home最小费用最大流
- poj 2195 Going Home (最小费用最大流)
- poj2195 Going Home 最小费用最大流
- POJ 2195 Going Home(最小费用最大流)
- POJ 2195 Going Home (最小费用最大流)
- POJ 2195 Going Home(最小费用最大流)
- POJ-2195 Going Home (最小费用最大流初学 && 最大权二分匹配—KM算法)
- [poj] 2195 Going Home || 最小费用最大流
- POJ-2195 Going Home(最小费用最大流)
- POJ 2195 Going Home 最小费用最大流(模板题)
- 最小费用最大流-POJ-2195-Going Home