最短路,网络流(HDU 5294,Tricks Device)
来源:互联网 发布:java 全栈开发框架 编辑:程序博客网 时间:2024/06/10 02:08
最短路+网络流算是很经典的套路了。
但是自己还是一直WA得不明所以。
原因是自己对edmondskarp算法的不理解。
首先,这道题的图是无向图,这点从题干中可以很容易的得到。
跑完Dijkstra后,我们得到了一个最短路树。
最早听说最短路树的概念是在大白书P330上。
意思是Dijkstra算法跑完以后会得到一个p数组,表示s到v的最短路径中v的前一个节点。
显然p数组能表示一个以s为根的树,如果想要从原点出发沿着最短路走到任意其他点,只要顺着树上的边走即可。
但是,最短路不唯一,最短路树对每一个节点只标出了一个最短路,如果非要标记出所有最短路的话,树形结构肯定是不够用的。
事实上,对于没有负环的图,所有可能的最短路会形成一个有向无环图。
我们也不需要弄一个什么结构去记录它,d数组就是一个最好的记录。
我们只需要沿着d[e.to]==d[e.from]+e.dist的方向走就ok了。
虽然有时候会走到死胡同,从而导致多了一些不必要的搜索,但是这不会慢太多,而且也没什么更简单实用的方法了。
我们就利用d数组的记录去建立一个网络流,网络流的边是有向边,每个有向边都有一个正向弧和一个反向弧。反向弧是为了反向增广,这和再加一条反向的有向边是不一样的。
我们应该利用最短路的有向无环图去建立一个有向网络流。如果建成无向网络流那就错了。
总结一下:
1、对原图建立无向图。
2、对原图跑Dijkstra得到最短路的有向无环图。
3、在这个有向无环图上跑bfs得到通过边数最少的最短路。
4、对这个有向无环图建立有向网络流,跑Edmondskarp得到最大流或最小割。
代码
#include<bits/stdc++.h>using namespace std;const int maxn = 2010;const int inf = 0x3f3f3f3f;struct Edge{ int from,to,dist,cap,flow;};struct HeapNode{ int d,u; bool operator < (const HeapNode& rhs) const { return d>rhs.d; }};struct Dijkstra_EdmondsKarp{ int n,m; vector<Edge>edges; vector<int>G[maxn]; int d[maxn]; int done[maxn]; int p[maxn]; int a[maxn]; int dd[maxn]; void init(int n) { this->n=n; for(int i=1;i<=n;i++) G[i].clear(); edges.clear(); } void Add_Edge(int from,int to,int dist) { edges.push_back((Edge){from,to,dist,1,0}); edges.push_back((Edge){to,from,dist,0,0}); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } void dijkstra(int s) { for(int i=1;i<=n;i++) { d[i]=inf; done[i]=0; } d[s]=0; priority_queue<HeapNode>q; q.push((HeapNode){0,s}); while(!q.empty()) { HeapNode now=q.top(); q.pop(); int u=now.u; if(done[u]) continue; done[u]=1; for(int i=0;i<(int)G[u].size();i++) { Edge&e = edges[G[u][i]]; if(e.cap==0) continue; if(d[e.to]>d[e.from]+e.dist) { d[e.to]=d[e.from]+e.dist; q.push((HeapNode){d[e.to],e.to}); } } } } int Maxflow(int s,int t) { int flow=0; while(1) { for(int i=1;i<=n;i++) a[i]=0; a[s]=inf; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<(int)G[u].size();i++) { Edge& e= edges[G[u][i]]; bool f=false; if(d[e.to]-d[e.from]==e.dist&&e.cap==1) f=true; if(d[e.from]-d[e.to]==e.dist&&e.cap==0) f=true; if(!f) continue; if(!a[e.to]&&e.cap>e.flow) { a[e.to]=min(a[e.from],e.cap-e.flow); p[e.to]=G[u][i]; q.push(e.to); } } if(a[t]) break; } if(!a[t]) break; for(int u=t;u!=s;u=edges[p[u]].from) { edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } flow+=a[t]; } return flow; } int bfs(int s,int t) { if(s==t) return 0; for(int i=1;i<=n;i++) dd[i]=0; queue<int>q; q.push(1); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<(int)G[u].size();i++) { Edge& e= edges[G[u][i]]; if(d[e.to]-d[e.from]==e.dist&&!dd[e.to]) { dd[e.to]=dd[e.from]+1; if(e.to==t) return dd[e.to]; q.push(e.to); } } } return m/4; }}DIJEDK;int N,M;void solve(){ int u,v,w; DIJEDK.init(N); for(int i=1;i<=M;i++) { scanf("%d %d %d",&u,&v,&w); DIJEDK.Add_Edge(u,v,w); DIJEDK.Add_Edge(v,u,w); } DIJEDK.dijkstra(1); printf("%d ",DIJEDK.Maxflow(1,N)); printf("%d\n",M-DIJEDK.bfs(1,N));}int main(){ while(scanf("%d %d",&N,&M)==2) solve(); return 0;}
0 0
- 最短路,网络流(HDU 5294,Tricks Device)
- 【网络流+最短路】 HDU 5294 Tricks Device
- HDU 5294 Tricks Device (最短路+网络流)
- hdu 5294 Tricks Device(最短路)
- hdu 5294 Tricks Device(最短路+最大流)
- hdu 5294 Tricks Device(最短路 + 最大流)
- 【HDU 5294】Tricks Device(最短路+最大流)
- HDU 5294 Tricks Device(最短路+最大流)
- hdu 5294 Tricks Device(最短路+网络流(最小割))
- hdu 5294 - Tricks Device(2015 Multi-University Training Contest 1 )最短路+网络流
- HDU 5294 Tricks Device 残余网络(最短路+最大流)**
- Tricks Device (hdu 5294 最短路+最大流)
- hdu 5294 Tricks Device 最短路+最大流
- 多校 hdu 5294 Tricks Device 最短路+最大流
- HDU 5294 Tricks Device (最大流+最短路)
- hdu 5294 Tricks Device (最短路+最大流)
- HDU 5294Tricks Device(最短路+最大流)
- HDU 5294 Tricks Device(最短路+最大流)
- 数据库笔记 7
- jquery 选择器
- linux命令记录
- 文件操作与数据存储json
- 机器学习实战之knn算法
- 最短路,网络流(HDU 5294,Tricks Device)
- Nginx+Tomcat配置集群session共享
- HDUoj Virtual Friends (并查集
- java实现一个简单的代理服务器
- stm32在keil5中新建工程[0]
- codeforces 55D Beautiful numbers(数位dp)
- 4.3考试解题报告
- 17.5读书季-开启
- ubuntu 常用命令