网络流 费用流选作 (BZOJ1877)
来源:互联网 发布:华为武汉研究所光网络 编辑:程序博客网 时间:2024/06/05 19:28
算法
处理最小费用最大流问题时,笔者最经常使用的算法是连续最短路算法。比较符合笔者很弱的代码能力,而且理解起来较为简单。
因为边的描述中多了权值这一元素,所以在建图的时候应该与最大流算法有些微小的差异。相同的地方是,两种问题都需要建反向边且反向边的流量都是0,对于边的权值,我们将反向边的权值设为正边的权值的相反数。
连续最短路算法的流程如下:
- hhh
- 用spfa找出图中所有可行路径(不包含流量为0的边的路径)具有最短距离的路径,如果有可行路径则进行第二步,否则跳至第3步;
- 对spfa中处理出的路径进行增广,并将这条路径的流量加入答案,将这条路径上边的权值和加入答案;
- 算法结束。
例题选讲
~
BZOJ1877 晨跑
题目大意
给出一个有向图,每个点能且只能经过一次,注明每一条边的权值。问在从起点到重点的路径尽可能多路径的权值和最短的情况下,最多的路径条数和最小的花费。
思路&题解
我们发现这道题里引入了权值这个量,所以是一个费用流相关问题。因为每一个点只能通过一次,所以我们采用和上一篇文章一样的方法:把每一个点拆成两个点,并在两个点中间连上一条流量为1权值为0的边,以出发点为源点,以终点为汇点,跑一遍最小费用最大流即可。
代码
/************************************************************** Problem: 1877 User: CHN Language: C++ Result: Accepted Time:1200 ms Memory:14280 kb****************************************************************/#include <cstdio>#include <cstdlib>#include <cstring>#include <queue>#include <iostream>using namespace std;#define pos1(k) (k+1)#define pos2(k) (k+n+1)const int maxn=int(1e5)+10;const int INF=int(1e9)+7;int n,m;int S,T;int ans_flow=0;int ans_dis=0;struct Edge { int from,to; int val,flow; int next;}eage[maxn*6];int head[maxn];int tot=-1;void add(int x,int y,int f,int v) { eage[++tot].from=x; eage[tot].to=y; eage[tot].val=v; eage[tot].flow=f; eage[tot].next=head[x]; head[x]=tot; std::swap(x,y); f=0; v=-v; eage[++tot].from=x; eage[tot].to=y; eage[tot].val=v; eage[tot].flow=f; eage[tot].next=head[x]; head[x]=tot;}void init() { memset(head,-1,sizeof head); tot=-1;}int dis[maxn];bool used[maxn];int pre[maxn];queue <int> que;void dfs();bool spfa() { while(que.size()) que.pop(); fill(dis,dis+maxn,INF); memset(used,false,sizeof used); dis[S]=0; used[S]=true; que.push(S); while(que.size()) { int u=que.front(); que.pop(); used[u]=false; for(int i=head[u];~i;i=eage[i].next) if(eage[i].flow) { int v=eage[i].to; if(dis[v]<=dis[u]+eage[i].val) continue; dis[v]=dis[u]+eage[i].val; pre[v]=i; if(!used[v]) { used[v]=true; que.push(v); } } } if(dis[T]>=INF) return false; ans_dis+=dis[T]; return true;}void dfs() { int now=T,p=pre[T]; int min_flow=INF; for(;now!=S;) { min_flow=std::min(min_flow,eage[p].flow); now=eage[p^1].to; p=pre[now]; } now=T,p=pre[T]; for(;now!=S;) { eage[p].flow-=min_flow; eage[p^1].flow+=min_flow; now=eage[p^1].to; p=pre[now]; } ans_flow+=min_flow; return;}void Min_cost_Max_flow() { while(spfa()) dfs();}int main() { scanf("%d%d",&n,&m); init(); S=pos1(1)-1; T=pos2(n)+1; add(S,pos1(1),INF,0); add(pos2(n),T,INF,0); add(pos1(1),pos2(1),INF,0); add(pos1(n),pos2(n),INF,0); for(int i=2;i<n;i++) add(pos1(i),pos2(i),1,0); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(pos2(x),pos1(y),1,z); } Min_cost_Max_flow(); printf("%d %d\n",ans_flow,ans_dis); return 0;}
1 0
- 网络流 费用流选作 (BZOJ1877)
- bzoj1877(费用流)
- [bzoj1877][网络流-费用流]晨跑
- [BZOJ1877][SDOI2009]晨跑(费用流)
- bzoj1877: [SDOI2009]晨跑(费用流)
- bzoj1877 [SDOI2009]晨跑(费用流)
- bzoj1877 晨跑 费用流
- [BZOJ1877]SDOI2009晨跑|费用流
- bzoj1877[SDOI2009]晨跑【费用流】
- 【bzoj1877】【SDOI2009】【晨跑】【费用流】
- bzoj1877 SDOI2009晨跑 费用流
- [bzoj1877][SDOI2009]晨跑 费用流
- BZOJ1877(最小费用最大流+拆点)
- Bzoj1877 SDOI 2009 晨跑 费用流
- 费用流 模板【SDOI2009】bzoj1877 晨跑
- 费用流——BZOJ1877/Luogu2153 [SDOI2009]晨跑
- 网络流与费用流(下)费用流
- bzoj1834(网络流+费用流)
- Too many Cluster redirections?问题
- LTE_1 空中接口
- gem5学习5——源代码文件结构作用介绍
- Spring学习笔记三:面向切面的Spring
- 浅析C++的构造函数和析构函数
- 网络流 费用流选作 (BZOJ1877)
- 博客开通啦,以后就在这里记录我的程序开发生涯,每天进步一点点
- LeetCode Letter Combinations of a Phone Number
- 在Visual Studio上编写自己的第三方库
- 基数排序之定长字典排序
- RingBuffer 笔记
- Message Queue学习笔记 --- 消息队列的两种模式
- 股票入门基础知识22:财务健康比率——判断公司实力
- 优化EXCEL导出的功能代码