• 洛谷P4015 运输问题 网络流24题


    看了下SPFA题解,一个一个太麻烦了,另一个写的很不清楚,而且注释都变成了"????"不知道怎么过的,于是自己来一发SPFA算法。

    Part 1.题意

    M 个仓库,卖给 N 个商店,两个问,第一问求运价最小值,第二问最大值。

    显然是一个最小费用最大流(MCMF)。

    Part 2.思路

    1.连让每个仓库连接一个超级源点 SS ,费用(dis)为0,流量为仓库的流量,表示每个仓库最多可以运出多少货物。

    2.让每一个仓库连接每一家商店,边权为 cost[i][j] ,其中,i为仓库编号,j为商店编号编号,流量为 need[j] ,其实流量可以取得范围是  [need[j]...INF] ,另外如果出现 need[j] <这个仓库货物量的情况也可以不怕(这时候取值的下限变成 min(hw[i],need[j]) ) hw指的是这家仓库的货物,还有注意编号的范围(我默认超级源点是 00 ,仓库是 1……n ,商店是 n+1……n+m ,超级汇点是 10000

    3.让每一家商店连接超级汇点 TT

    图像帮助理解: 

    Part 3.代码

    现在代码就好办了 注释给的很清楚

      1 #include<iostream>
      2 #include<cmath>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<queue>
      6 #include<stack>
      7 #include<vector>
      8 #include<map>
      9 #include<set>
     10 #include<algorithm>
     11 
     12 #define I_copy_this_answer return 0;
     13 
     14 using namespace std;
     15 
     16 int n,m,head[1100],size=1;
     17 int mmx=1000,mincost,maxwater;
     18 int flow[1100];
     19 int need[1100],cost[310][310];
     20 int pre[1100],las[1100],dis[1100],vis[1100],hw[1100];
     21 
     22 struct edge{
     23     int next,to,dis,flow; 
     24 }e[100860]; 
     25 
     26 void addedge(int next,int to,int dis,int flow)
     27 {
     28     e[++size].to=to;
     29     e[size].dis=dis;
     30     e[size].flow=flow;
     31     e[size].next=head[next];
     32     head[next]=size;
     33 }
     34 
     35 int spfa(int s)
     36 {
     37     memset(flow,0x3f,sizeof(flow));
     38     memset(dis,0x3f,sizeof(dis));
     39     memset(vis,0,sizeof(vis));
     40     queue <int> q;
     41     q.push(s);
     42     dis[s]=0;
     43     vis[s]=1;
     44     pre[mmx]=-1;  //(其实只要不是与p直接连的点(n+1......n+m)就可以了 
     45     while(!q.empty())
     46     {
     47         int t=q.front();
     48         q.pop();
     49         vis[t]=0;
     50         int i,j,k,l;
     51         for(i=head[t];i;i=e[i].next)
     52         {
     53             j=e[i].to;
     54             k=e[i].dis;
     55             l=e[i].flow;
     56             if(dis[t]+k<dis[j]&&l>0)  //没有流量的话这条路就增广不了,最短距离是建立在增广路存在的基础上的 
     57             {
     58                 dis[j]=dis[t]+k;
     59                 las[j]=i;  //las指的是这个点(j)与上个点(t)相连的边的编号 
     60                 pre[j]=t;  //pre指的是这条路径上这个点(j)的上一个点 
     61                 flow[j]=min(flow[t],l);  //把当前边流量与上个点的流量对比,解决出现仓库货物比需要的少的情况 
     62                 if(!vis[j])
     63                 {
     64                     q.push(j);
     65                     vis[j]=1;
     66                 }
     67             }
     68         }
     69     }
     70     return pre[mmx]!=-1;  //如果不是这个值就说明这个点被刷新,增广成功 
     71 }
     72 
     73 void mcmf()
     74 {
     75     while(spfa(0))
     76     {
     77         mincost+=dis[mmx]*flow[mmx];   //从源点出发到汇点的单位费用再乘以单位,由于每次只增广一条路,而且仓库和商店是直接连接的,可以这样写 
     78         int t=mmx;
     79         while(t!=0)
     80         {
     81             e[las[t]].flow-=flow[mmx];  //回溯,修改每条边的流量,因为该算法中途找到的增广路不是最后的增广路,所以这个要等到最后来改变 
     82             e[las[t]^1].flow+=flow[mmx];
     83             t=pre[t];
     84         }
     85     }
     86 }
     87 
     88 void build_edge(int t)
     89 {
     90     int i,j;
     91     for(i=1;i<=m;i++)
     92     {
     93         addedge(0,i,0,hw[i]);
     94         addedge(i,0,0,0);
     95     } 
     96     for(i=1;i<=m;i++)
     97     for(j=1;j<=n;j++)
     98     {
     99         addedge(i,j+m,cost[i][j]*t,need[j]);
    100         addedge(j+m,i,-cost[i][j]*t,0);
    101     }
    102     for(i=1;i<=n;i++)
    103     {
    104         addedge(i+m,mmx,0,need[i]);
    105         addedge(mmx,i+m,0,0);
    106     }
    107 }
    108 
    109 int main()
    110 {
    111     int i,j;
    112     scanf("%d %d",&m,&n);
    113     for(i=1;i<=m;i++)
    114     {
    115         int t1;
    116         scanf("%d",&hw[i]); 
    117     }
    118     for(i=1;i<=n;i++)
    119         scanf("%d",&need[i]);
    120     for(i=1;i<=m;i++)
    121     for(j=1;j<=n;j++)
    122         scanf("%d",&cost[i][j]);  //读入,与上面的cost,need,hw如果不明白可以对照输入格式看代表什么意思 
    123     build_edge(1);  //建立边权为正的边,跑最小费用最大流 
    124     mcmf();//最小费用最大流(Min Cost Max Flow )的缩写 
    125     printf("%d",mincost); 
    126     maxwater=0;
    127     mincost=0; 
    128     size=1;
    129     memset(head,0,sizeof(head));
    130     build_edge(-1);
    131     mcmf();
    132     printf("
    %d",-mincost);
    133     I_copy_this_answer
    134 }
  • 相关阅读:
    Java反射
    浅谈page,request,session,application四种范围
    使用MySQL连接池
    SQL注入漏洞的演示及解决办法
    JDBC工具类的提取
    JDBC使用过程
    MYSQL常用函数
    MySQL数据操作
    MySQL存储引擎
    Python核心技术与实战——六|异常处理
  • 原文地址:https://www.cnblogs.com/zsx6/p/11174387.html
Copyright © 2020-2023  润新知