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

匿名 (未验证) 提交于 2019-12-02 23:47:01

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

Part 1.题意

M 个仓库,卖给 N

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

Part 2.˼·

S

cost[i][jneed[j[need[j]...INFneed[jmin(hw[i],need[j]01……nn+1……n+m10000

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("\n%d",-mincost); 133     I_copy_this_answer 134 }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!