洛谷P3381【模板】最小费用最大流

来源:互联网 发布:乔丹最后一个赛季数据 编辑:程序博客网 时间:2024/05/16 18:47

题目链接:

https://www.luogu.org/problem/show?pid=3381

题目大意:

求最大流和费用流

题目思路:

最小费用最大流模板题,注意事项都在模板中标注。

代码:

#include <bits/stdc++.h>    using namespace std;  int n,m;  int S,T;  //S是源点 T是汇点 const int MAXN = 5010;  //点的最大值const int MAXM = 100100;  //边的最大值const int INF = 0x7fffffff;  //inf开错 可能会t struct Edge{      int to,next,cap,flow;      int cost;  } edge[MAXM];  int head[MAXN],tol;  int pre[MAXN];  int dis[MAXN];  bool vis[MAXN];  int N;  void init()  //不要忘了init() {      N = n+10;   //不要开的过大 可能会T     tol = 0;      memset(head,-1,sizeof(head));//S=0;//源点 超级源点可以自己设置 //T=n+1;  //汇点 ,我在这里开n+10结果超时了,不明觉厉 超级汇点可以自己设置 }  void addedge(int u,int v,int cap,double cost)  //建边,cap是容量cost是费用 {      edge[tol].to = v;      edge[tol].cap = cap;      edge[tol].cost = cost;      edge[tol].flow = 0;      edge[tol].next = head[u];      head[u] = tol++;      edge[tol].to = u;      edge[tol].cap = 0;      edge[tol].cost = -cost;      edge[tol].flow = 0;      edge[tol].next = head[v];      head[v] = tol++;  }  bool spfa(int s,int t)  //s是源点 t是汇点 {      queue<int>q;      for(int i = 0; i < N; i++)      {          dis[i] = INF;          vis[i] = false;          pre[i] = -1;      }      dis[s] = 0;      vis[s] = true;      q.push(s);      while(!q.empty())      {            int u = q.front();          q.pop();          vis[u] = false;          for(int i = head[u]; i != -1; i = edge[i].next)          {              int v = edge[i].to;              if(edge[i].cap > edge[i].flow &&                    dis[v] - dis[u] - edge[i].cost>0 ){  //浮点数加精度判断,否则会T                 dis[v] = dis[u] + edge[i].cost;                  pre[v] = i;                  if(!vis[v]){                      vis[v] = true;                      q.push(v);                  }              }          }      }      if(pre[t] == -1)return false;      else return true;  }  int minCostMaxflow(int s,int t,int &cost){  //cost返回的是最小费用     int flow = 0; //这里的flow返回的是最大流     cost = 0;      while(spfa(s,t)){          int Min = INF;          for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]){              if(Min > edge[i].cap - edge[i].flow)                      Min = edge[i].cap - edge[i].flow;          }          for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]){              edge[i].flow += Min;              edge[i^1].flow -= Min;              cost += edge[i].cost * Min;          }          flow += Min;      }      return flow;  //求出来最大流 }         int main(){      scanf("%d%d%d%d",&n,&m,&S,&T);    init();//不要忘了 init     for(int i=1;i<=m;i++){    int ui,vi,wi,fi;    scanf("%d%d%d%d",&ui,&vi,&wi,&fi);//求最大费的时候,******************只需要将费用取相反数即可 *********************     addedge(ui,vi,wi,fi);} int ans=0;//ans求的是最小费用 printf("%d ",minCostMaxflow(S,T,ans));printf("%d\n",ans);    return 0;  }  




原创粉丝点击