图论:有源汇有上下界最小流

这次就是最小流了

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const ll INF=0x3f3f3f3f3f3f3f3f;
  5 const int N=50200;
  6  
  7 struct node{
  8     ll t,cap,flow,next;    //cap容量,flow流量
  9 }e[N*12];
 10 int head[N],vis[N],cnt;
 11 void add(int u,int v,ll cap)   //u->v容量为cap
 12 {
 13     e[cnt]=node{v,cap,0,head[u]};
 14     head[u]=cnt++;
 15     e[cnt]=node{u,0,0,head[v]};   //容量为0的反向边
 16     head[v]=cnt++;
 17 }
 18 int d[N];    //bfs深度
 19 bool bfs(int s,int t)   //O(n+m)
 20 {
 21     memset(d,0,sizeof(d));
 22     queue<int>q;
 23     q.push(s);
 24     d[s]=1;
 25     while(!q.empty())
 26     {
 27         int u=q.front();q.pop();
 28         for(int i=head[u];~i;i=e[i].next)
 29         {
 30             int v=e[i].t;
 31             if(d[v]==0&&e[i].cap-e[i].flow>0)
 32             {
 33                 d[v]=d[u]+1;
 34                 q.push(v);
 35             }
 36         }
 37     }
 38     return d[t]>0;     //存在增广路
 39 }
 40 ll dfs(int s,int t,ll minedge)
 41 {
 42     if(s==t)return minedge;
 43     ll flow=0;    //从当前s点流出的流量
 44     for(int &i=vis[s];~i;i=e[i].next)
 45     {
 46         int v=e[i].t;
 47         if(d[v]==d[s]+1&&e[i].cap-e[i].flow>0)   //层次关系&&有剩余流量
 48         {
 49             ll temp=dfs(v,t,min(minedge-flow,e[i].cap-e[i].flow));
 50             e[i].flow+=temp;    //流量增加
 51             e[i^1].flow-=temp;    //反向边流量减少
 52             flow+=temp;    //flow已分配的流量
 53             if(flow==minedge)return flow;  //已达到祖先的最大流,无法再大,剪枝
 54         }
 55     }
 56     if(flow==0)d[s]=0;   //此点已无流,标记掉
 57     return flow;
 58 }
 59 ll dinic(int s,int t)   //一定要建立反向边cap=0
 60 {
 61     ll maxflow=0;
 62     while(bfs(s,t))   //有增广路
 63     {
 64         memcpy(vis,head,sizeof(head));
 65         maxflow+=dfs(s,t,INF);
 66     }
 67     return maxflow;
 68 }
 69  
 70  
 71 ll bout[N],low[N*10];
 72 int main()
 73 {
 74     int n,m,s,t,u,v;
 75     ll b,c;
 76     while(cin>>n>>m>>s>>t)
 77     {
 78         memset(head,-1,sizeof(head));
 79         cnt=0;
 80         memset(bout,0,sizeof(bout));
 81         for(int i=0;i<m;i++)
 82         {
 83             scanf("%d%d%lld%lld",&u,&v,&b,&c);
 84             add(u,v,c-b);
 85             bout[u]+=b;
 86             bout[v]-=b;
 87             low[i]=b;
 88         }
 89         int ss=n+1,tt=n+2;
 90         ll sum=0;
 91         for(int i=1;i<=n;i++){
 92             if(bout[i]>0)sum+=bout[i],add(i,tt,bout[i]);
 93             if(bout[i]<0)add(ss,i,-bout[i]);
 94         }
 95         ll res=dinic(ss,tt);
 96         add(t,s,INF);
 97         res+=dinic(ss,tt);
 98         if(sum==res)
 99         {
100             printf("%lld\n",e[cnt-2].flow);
101         }
102         else printf("please go home to sleep\n");
103     }
104 }

 

转载于:https://www.cnblogs.com/aininot260/p/9623869.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值