网络流 费用流选作 (BZOJ1877)

来源:互联网 发布:华为武汉研究所光网络 编辑:程序博客网 时间:2024/06/05 19:28

算法

处理最小费用最大流问题时,笔者最经常使用的算法是连续最短路算法。比较符合笔者很弱的代码能力,而且理解起来较为简单。

因为边的描述中多了权值这一元素,所以在建图的时候应该与最大流算法有些微小的差异。相同的地方是,两种问题都需要建反向边且反向边的流量都是0,对于边的权值,我们将反向边的权值设为正边的权值的相反数。

连续最短路算法的流程如下:

  1. hhh
  2. 用spfa找出图中所有可行路径(不包含流量为0的边的路径)具有最短距离的路径,如果有可行路径则进行第二步,否则跳至第3步;
  3. 对spfa中处理出的路径进行增广,并将这条路径的流量加入答案,将这条路径上边的权值和加入答案;
  4. 算法结束。

例题选讲

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
原创粉丝点击