zoukankan      html  css  js  c++  java
  • 费用流的简单应用

    题目链接:luogu4013

     

    题目:

    给定一个由 n 行数字组成的数字梯形如下图所示。

     

    梯形的第一行有 m 个数字。从梯形的顶部的 m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。

    分别遵守以下规则:

    1. 从梯形的顶至底的 m 条路径互不相交;

    2. 从梯形的顶至底的 m 条路径仅在数字结点处相交;

    3. 从梯形的顶至底的 m 条路径允许在数字结点相交或边相交。

    输入输出格式

    输入格式:

    第 1 行中有 2 个正整数 m 和 n ,分别表示数字梯形的第一行有 m 个数字,共有 n 行。接下来的 n 行是数字梯形中各行的数字

    第 1 行有 m 个数字,第 2 行有 m+1个数字,以此类推。

    输出格式:

    将按照规则 1 ,规则 2 ,和规则 3 计算出的最大数字总和并输出,每行一个最大总和。

    输入输出样例

    输入样例:
    2 5
    2 3
    3 4 5
    9 10 9 1
    1 1 10 1 1
    1 1 10 12 1 1
    输出样例:
    66
    75
    77

     本来以为会是一道dp题,没想到是网络流。

      大致思路就是用费用来代表每个点的收益,然后用容量来控制这个点和边可以走多少次,最后跑最大费用最大流就行了。

    规则一:

    既然每个点只能走一次,就把每个点拆成两个点(i,a),(i,b),这两个点之间连一条容量为1,费用为i权值的边。既然每条边也不能相交(也就是不能重合),所以就从i向其左下和右下的点(j,a)分别连一条容量为一,费用为0的边。最后就是常用的建源点的汇点,建一个源点,将其与顶部的每个点连一条容量为1,费用为0的边(因为顶部的点也只能跑一次)。在建一个汇点,将其与底部 每个点连一条容量为1,费用为0的边。

    规则二:

    参考规则一进行修改即可。但是这次点可以重复走,所以就不拆点。既然边都是不能相交(重合),那就还是将点i与下面每条j连一条容量为1,费用为i权值的边。因为这次不拆点,所以要想把权值加进去,就得把这条连边的费用改为权值。然后源点的连边不变,因为每个路径的起点肯定不同。因为每个点(除了起点)可以走无数次,所以底部的点与汇点的连边容量为无穷大。费用为底部点的权值

    规则三:

    参考规则二,这次边也可以重复,所以就将每条从i到j的连边的容量改为无穷大。费用还是i的权值。顶部和底部的连边还是不变。

    最后每个规则跑一遍最大费用最大流,所得的费用就是答案。

    代码:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<queue>
      4 #include<cstring>
      5 using namespace std;
      6 const int INF=9999999;
      7 const int N=100000;
      8 int a[100][100],b[100][100],vis[N];
      9 int n,m,head[N],ejs;
     10 struct node
     11 {
     12     int u,v,nxt,w,siz;
     13 }edg[N];
     14 void add(int u,int v,int w,int siz)
     15 {
     16     edg[++ejs].v=v;
     17     edg[ejs].u=u;
     18     edg[ejs].w=w;
     19     edg[ejs].siz=siz;
     20     edg[ejs].nxt=head[u];
     21     head[u]=ejs;
     22     edg[++ejs].u=v;
     23     edg[ejs].v=u;
     24     edg[ejs].siz=0;
     25     edg[ejs].w=-w;
     26     edg[ejs].nxt=head[v];
     27     head[v]=ejs;
     28 }
     29 int rank[100][100],dis[N],faz[N],js;
     30 queue<int>q;
     31 int change(int i)
     32 {
     33     return i%2?i+1:i-1;
     34 }
     35 void clear()
     36 {
     37     memset(head,0,sizeof(head));
     38     memset(edg,0,sizeof(edg));
     39     ejs=0;
     40 }
     41 bool spfa(int s,int t)
     42 {
     43     for(int i=1;i<=t;++i) dis[i]=-INF;
     44     memset(vis,0,sizeof(vis));
     45     memset(faz,0,sizeof(faz));
     46     while(!q.empty()) q.pop();
     47     q.push(s);
     48     dis[s]=0;
     49     vis[s]=1;
     50     while(!q.empty())
     51     {
     52         int u=q.front();
     53         q.pop();
     54         vis[u]=0;
     55         for(int i=head[u];i;i=edg[i].nxt)
     56         {
     57             int v=edg[i].v;
     58             if(dis[u]+edg[i].w>dis[v]&&edg[i].siz)
     59             {
     60                 faz[v]=i;
     61                 dis[v]=dis[u]+edg[i].w;
     62                 if(!vis[v])
     63                 {
     64                     q.push(v);
     65                     vis[v]=1;
     66                 }
     67                 
     68             }
     69         }
     70     }
     71     if(dis[t]!=-INF) return 1;
     72     return 0;
     73 }
     74 int work(int s,int t)
     75 {
     76     int ans=0;
     77     while(spfa(s,t))
     78     {
     79         int k=t,minn=0x7fffff;
     80         int now=t;
     81         while(now!=s)
     82         {
     83             minn=min(edg[faz[now]].siz,minn);
     84             now=edg[faz[now]].u;
     85         }
     86         now=t;
     87         while(now!=s)
     88         {
     89             edg[faz[now]].siz-=minn;
     90             edg[change(faz[now])].siz+=minn;
     91             now=edg[faz[now]].u;
     92         }
     93         ans+=dis[t]*minn;
     94     }
     95     return ans;
     96 }
     97 void rules1()
     98 {
     99     clear();
    100     int s=0,t=js*2+1;
    101     for(int i=1;i<=m;++i)
    102     add(s,rank[1][i],0,1);
    103     for(int i=1;i<=m+n-1;++i)
    104     add(rank[n][i]+js,t,0,1);
    105     for(int i=1;i<=n;++i)
    106     for(int j=1;j<=i+m-1;++j)
    107     {
    108         
    109         add(rank[i][j],rank[i][j]+js,a[i][j],1);
    110         if(i==n) continue;
    111         add(rank[i][j]+js,rank[i+1][j],0,1);
    112         add(rank[i][j]+js,rank[i+1][j+1],0,1);
    113     }
    114     printf("%d
    ",work(s,t));
    115 }
    116 void rules2()
    117 {
    118     clear();
    119     int s=0,t=js+1;
    120     for(int i=1;i<=m;++i) add(s,rank[1][i],0,1);
    121     for(int i=1;i<m+n;++i) add(rank[n][i],t,a[n][i],INF);
    122     for(int i=1;i<n;++i)
    123     for(int j=1;j<=m+i-1;++j)
    124     {
    125         add(rank[i][j],rank[i+1][j],a[i][j],1);
    126         add(rank[i][j],rank[i+1][j+1],a[i][j],1);
    127     }
    128     printf("%d
    ",work(s,t));
    129 }
    130 
    131 void rules3()
    132 {
    133     clear();
    134     int s=0,t=js+1;
    135     for(int i=1;i<=m;++i) add(s,rank[1][i],0,1);
    136     for(int i=1;i<=n+m-1;++i) add(rank[n][i],t,a[n][i],INF);
    137     for(int i=1;i<n;++i)
    138     for(int j=1;j<=m+i-1;++j)
    139     {
    140         add(rank[i][j],rank[i+1][j],a[i][j],INF);
    141         add(rank[i][j],rank[i+1][j+1],a[i][j],INF);
    142     }
    143     printf("%d
    ",work(s,t));
    144 }
    145 int main()
    146 {
    147     scanf("%d%d",&m,&n);
    148     for(int i=1;i<=n;++i)
    149     {
    150         for(int j=1;j<=m+i-1;++j)
    151         {
    152             scanf("%d",&a[i][j]);
    153             rank[i][j]=++js;
    154         }
    155     }
    156     rules1();
    157     rules2();
    158     rules3();
    159     return 0;
    160  } 
    luogu4013
  • 相关阅读:
    JS 数组排序
    曾经跳过的坑------replace、替换斜杠反斜杠、时间格式化处理
    List排序、集合排序
    git远程覆盖本地的
    整理日期,整理时间段,将日期集合整理为时间段
    当数据库查询in使用超过1000个的处理方式,in超过1000的问题
    oracle一些语法
    idea中git操作
    idea鼠标放上去查看注释,idea查看注释
    idea更新git远程代码,查看代码改动了哪些
  • 原文地址:https://www.cnblogs.com/wxyww/p/9340122.html
Copyright © 2011-2022 走看看