HDU 4411 Arrest 费用流
2016-04-17 17:02
459 查看
费用流是每次找最短路然后沿着这条路增广,然后这条路因为增广了,所以就流量为0,相当于不存在了,所以可以继续找最短路,不怕出现重复,然后求的是全图的,这点切记
有n+1个城市,0市为警察局所在城市其中有k个警察,在其他n个城市中,均有小偷。有m条路,每条路有其特定路程,求k个警察将n个城市的小偷全抓捕到0市的最短路程。其中抓小偷必须从1、2、3、、、n按照城市号码严格递增顺序抓。
最小费用流的问题。样例输出解释:0->1->3(不抓小偷)->2->3->1->0。路程和为3+2+2+2+2+3=14。
设置超级源点s,超级汇点t。将0点与s和t建立容量为k,费用为0的边,并将其他n点拆掉。n个点与0点建立容量1费用为两点最短路的边,同时n个被拆出来的点与t建立容量为1费用为两点最短路的边,n个点与其被拆出来的点建立容量为1费用足够小的边(足够小的意思是保证不会出现s->0->t),跑一边最小费用,最后输出的时候把n个足够小费用加回去。
有n+1个城市,0市为警察局所在城市其中有k个警察,在其他n个城市中,均有小偷。有m条路,每条路有其特定路程,求k个警察将n个城市的小偷全抓捕到0市的最短路程。其中抓小偷必须从1、2、3、、、n按照城市号码严格递增顺序抓。
最小费用流的问题。样例输出解释:0->1->3(不抓小偷)->2->3->1->0。路程和为3+2+2+2+2+3=14。
设置超级源点s,超级汇点t。将0点与s和t建立容量为k,费用为0的边,并将其他n点拆掉。n个点与0点建立容量1费用为两点最短路的边,同时n个被拆出来的点与t建立容量为1费用为两点最短路的边,n个点与其被拆出来的点建立容量为1费用足够小的边(足够小的意思是保证不会出现s->0->t),跑一边最小费用,最后输出的时候把n个足够小费用加回去。
#include <iostream> #include <stdio.h> using namespace std; const int oo=1e9; const int maxm=1111111; const int maxn=220; const int ff=100000; int node,src,dest,edge; int head[maxn],p[maxn],dis[maxn],q[maxn],vis[maxn]; struct edgenode { int to; int flow; int cost; int next; } edges[maxm]; void prepare(int _node,int _src,int _dest); void addedge(int u,int v,int f,int c); bool spfa(); inline int min(int a,int b) { return a<b?a:b; } inline void prepare(int _node,int _src,int _dest) { node=_node; src=_src; dest=_dest; for (int i=0; i<node; i++) { head[i]=-1; vis[i]=false; } edge=0; } void addedge(int u,int v,int f,int c) { edges[edge].flow=f; edges[edge].cost=c; edges[edge].to=v; edges[edge].next=head[u]; head[u]=edge++; edges[edge].flow=0; edges[edge].cost=-c; edges[edge].to=u; edges[edge].next=head[v]; head[v]=edge++; } bool spfa() { int i,u,v,l,r=0,tmp; for (i=0; i<node; i++) dis[i]=oo; dis[q[r++]=src]=0; p[src]=p[dest]=-1; for (l=0; l!=r; ((++l>=maxn)?l=0:1)) { for (i=head[u=q[l]],vis[u]=false; i!=-1; i=edges[i].next) { if (edges[i].flow&&dis[v=edges[i].to]>(tmp=dis[u]+edges[i].cost)) { dis[v]=tmp; p[v]=i^1; if (vis[v]) continue; vis[q[r++]=v]=true; if (r>=maxn) r=0; } } } return p[dest]>=0; } int spfaflow() { int i,ret=0,delta; while (spfa()) { for (i=p[dest],delta=oo; i>=0; i=p[edges[i].to]) { delta=min(delta,edges[i^1].flow); } for (int i=p[dest]; i>=0; i=p[edges[i].to]) { edges[i].flow+=delta; edges[i^1].flow-=delta; } ret+=delta*dis[dest]; } return ret; }//以上是费用流模板 int a[maxn][maxn]; int main() { int n,m,k; while(~scanf("%d%d%d",&n,&m,&k) && (n || m || k)) { //init(); int s=n*2+1; int t=s+1; prepare(n*2+3,s,t); //for(int i=0; i<=n; i++) // for(int j=0; j<=n; j++) for(int i=0; i<m; i++) for(int j=0; j<m; j++) if (i!=j) a[i][j]=oo; else a[i][j]=0; //while(m--) for(int i=0; i<m; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); a[u][v]=a[v][u]=min(w,a[u][v]); } for(int l=0;l<=n;l++)//Floyd求最短路 for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) if(a[i][l]<oo && a[l][j]<oo && a[i][l]+a[l][j]<a[i][j]) a[i][j]=a[i][l]+a[l][j]; addedge(s,0,k,0);//源点与0点,容量为k,费用为0 addedge(0,t,k,0);//汇点与0点,容量为k,费用为0 for(int i=1; i<=n; i++) { for(int j=i+1; j<=n; j++) { addedge(i+n,j,1,a[i][j]);//先到i点再到j点 } addedge(0,i,1,a[0][i]);//0点到i点,容量为1,费用为最短路 addedge(i,i+n,1,-ff);//拆点,cost值设为适当小的值,以免导致s->0->t addedge(i+n,t,1,a[0][i]);//i点到0点,容量为1,费用为最短路 } printf("%d\n",spfaflow()+ff*n); } return 0; }
相关文章推荐
- 初学图论-Kahn拓扑排序算法(Kahn's Topological Sort Algorithm)
- 初学图论-Bellman-Ford单源最短路径算法
- 初学图论-DAG单源最短路径算法
- 初学图论-Dijkstra单源最短路径算法
- 初学图论-Dijkstra单源最短路径算法基于优先级队列(Priority Queue)的实现
- 封装好的Folyd建图,C++源码
- LCA模板
- 图论学习笔记之一——Floyd算法
- 【LCA】SPOJ QTREE2
- poj 3249 Test for Job 最长路
- HDU 2544
- Timus 1557 Network Attack DFS+各种各种...
- HDU1289 Tarjan-模板题
- Poj2638 网络流+最短路+二分答案
- Aizu1311 分层图最短路 (...大概)
- BZOJ3275 Number (最小割)
- [笔记] 网络流-最大流 POJ-1273\HDU-4240
- HDU 3631 Shortest Path
- 上下界网络流初探
- Dijkstra算法