ZOJ 2314 带上下界的可行流

对于无源汇问题,方法有两种.

1 从边的角度来处理. 新建超级源汇, 对于每一条有下界的边,x->y, 建立有向边 超级源->y ,容量为x->y下界,建立有向边
x-> 超级汇,容量为x->y下界.建立有向边 x->y,容量为x->y的上界减下界.

2 从点的角度来处理. 新建超级源汇,对于每个点流进的下界和为 in, 流出此点的下界和为out.如果in > out. 建立有向边
超级源->i,容量为in-out.反之,建立有向边 i->超级汇,容量为out-in.

如果超级源的每一条出边都满流,则存在一个可行流,可行流的流量就是每一条逆向边的流量+ 此边下界.

从点的角度的处理方法是边的处理方法的拓展.基于边的处理比较容易理解,但是复杂度较高.

下面是基于点的处理的程序:

   1:  /*
   2:      带上下界的可行流
   3:  */
   4:  #include<iostream>
   5:  #include<cmath>
   6:  #include<memory>
   7:  #include <string.h>
   8:  #include <cstdio>
   9:  using namespace std;
  10:   
  11:  #define V 300      // vertex
  12:  #define E  40800     // edge
  13:  #define INF 0x3F3F3F3F  // 1061109567
  14:   
  15:  int i,j,k;
  16:  #define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
  17:  #define snuke(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
  18:   
  19:  struct MaxFlow
  20:  {
  21:      struct Edge
  22:      {
  23:          int v, w, next;     //w for capicity
  24:          int lb,up;
  25:      } edge[E];
  26:   
  27:      int head[V];          // head[u]表示顶点u第一条邻接边的序号, 若head[u] = -1, u没有邻接边
  28:      int e;                // the index of the edge
  29:      int src, sink;
  30:      int net[V];              // 流入此节点的流的下界和 - 流出此节点的流的下界和,对于带上下界的来进行使用
  31:   
  32:   
  33:      void addedge(int  u, int v, int w, int lb = 0, int up = INF, int rw = 0)
  34:      {
  35:          edge[e].v = v;
  36:          edge[e].w= w;
  37:          edge[e].next = head[u];
  38:          edge[e].lb = lb, edge[e].up = up;
  39:          head[u] = e++;
  40:          // reverse edge  v -> u
  41:          edge[e].v = u;
  42:          edge[e].w = rw;
  43:          edge[e].lb = lb, edge[e].up = up;
  44:          edge[e].next = head[v];
  45:          head[v] = e++;
  46:      }
  47:   
  48:      int ISAP(int VertexNum )
  49:      {
  50:          int u, v, max_flow, aug, min_lev;
  51:          int curedge[V], parent[V], level[V];
  52:          int count[V], augment[V];
  53:   
  54:          memset(level, 0, sizeof(level));
  55:          memset(count, 0, sizeof(count));
  56:          REP(i,VertexNum+1) curedge[i] = head[i];
  57:          max_flow = 0;
  58:          augment[src] = INF;
  59:          parent[src] = -1;
  60:          u = src;
  61:   
  62:          while (level[src] < VertexNum)
  63:          {
  64:              if (u == sink)
  65:              {
  66:                  max_flow += augment[sink];
  67:                  aug = augment[sink];
  68:                  for (v = parent[sink]; v != -1; v = parent[v])
  69:                  {
  70:                      i = curedge[v];
  71:                      edge[i].w  -= aug;
  72:                      edge[i^1].w  += aug;
  73:                      augment[edge[i].v] -= aug;
  74:                      if (edge[i].w == 0) u = v;
  75:                  }
  76:              }
  77:              for (i = curedge[u]; i != -1; i = edge[i].next)
  78:              {
  79:                  v = edge[i].v;
  80:                  if (edge[i].w > 0 && level[u] == (level[v]+1))
  81:                  {
  82:                      augment[v] = min(augment[u], edge[i].w);
  83:                      curedge[u] = i;
  84:                      parent[v] = u;
  85:                      u = v;
  86:                      break;
  87:                  }
  88:              }
  89:              if (i == -1)
  90:              {
  91:                  if (--count[level[u]] == 0) break;
  92:                  curedge[u] = head[u];
  93:                  min_lev = VertexNum;
  94:                  for (i = head[u]; i != -1; i = edge[i].next)
  95:                      if (edge[i].w > 0)
  96:                          min_lev = min(level[edge[i].v], min_lev);
  97:                  level[u] = min_lev + 1;
  98:                  count[level[u]]++;
  99:                  if (u != src ) u = parent[u];
 100:              }
 101:          }
 102:          return max_flow;
 103:      }
 104:      void solve()
 105:      {
 106:          int T; cin>>T;
 107:          for(int cas =1; cas <=T; cas++)
 108:          {
 109:              int N,M; cin>>N>>M;
 110:              e = 0;
 111:              memset(head, -1, sizeof(head));
 112:              memset(net, 0, sizeof(net));
 113:              int a,b,c,d;
 114:              for(int i=1; i<=M;i++)
 115:              {
 116:                  scanf("%d%d%d%d", &a, &b, &c, &d);
 117:                  net[b] += c; net[a] -= c;
 118:                  addedge(a,b,d-c, c,d);
 119:              }
 120:              // 无源汇,这两个是super src, super sink.
 121:              src =N+1; sink = N+2;
 122:              for(int i=1; i<=N; i++)
 123:              {
 124:                  if(net[i] > 0)
 125:                      addedge(src, i, net[i]);
 126:                  else
 127:                      addedge(i, sink, -net[i]);
 128:              }
 129:              ISAP(N+2);
 130:              bool flag = true;
 131:              for (i = head[src]; i != -1; i = edge[i].next)
 132:              {
 133:                  if(edge[i].w !=0)
 134:                  {
 135:                      flag = false;
 136:                      break;
 137:                  }
 138:              }
 139:              if(flag)
 140:              {
 141:                  cout<<"YES"<<endl;
 142:                  for(int i=0; i<M;i++)
 143:                  {
 144:                      cout<<edge[i*2+1].w + edge[i*2+1].lb<<endl;
 145:                  }
 146:                  cout<<endl;
 147:              }else
 148:              {
 149:                  cout<<"NO"<<endl;
 150:                  cout<<endl;
 151:              }
 152:          }
 153:   
 154:      }
 155:  }sap;
 156:   
 157:  int main()
 158:  {
 159:  //    freopen("1.txt","r",stdin);
 160:      sap.solve();
 161:      return 0;
 162:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

时间: 2025-01-07 00:50:09

ZOJ 2314 带上下界的可行流的相关文章

POJ 2396 Budget (有源汇有上下界的可行流)

POJ 2396 Budget 链接:http://poj.org/problem?id=2396 题意:给定一个M*N的矩阵,给定每行每列的和,以及其中一些值的限定条件,问能否构成一个可行的矩阵. 思路: 添加一个源点,向每行连边,每条边的上下界都为该行的和:添加一个汇点,每列向汇点连边,边的上下界都为该列的和.然后每行向每列连边,边的上下界一开始为(0,INF),之后通过一些限定条件更新. 现在问题成了求一个有源汇有上下界的可行流.只需要再添加一个超级源点,一个超级汇点,并且将原图的汇点向源

[ACdream 1211 Reactor Cooling]无源无汇有上下界的可行流

题意:无源无汇有上下界的可行流 模型 思路:首先将所有边的容量设为上界减去下界,然后对一个点i,设i的所有入边的下界和为to[i],所有出边的下界和为from[i],令它们的差为dif[i]=to[i]-from[i],根据流量平衡原理,让出边和入边的下界相抵消,如果dif[i]>0,说明入边把出边的下界抵消了,还剩下dif[i]的流量必须要流过来(否则不满足入边的下界条件),这时从源点向i连一条容量为dif[i]的边来表示即可,如果dif[i]<0,同理应该从i向汇点连一条容量为-dif[i

【BZOJ2406】矩阵 二分+有上下界的可行流

[BZOJ2406]矩阵 Description Input 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. Output 第一行,输出最小的答案: Sample Input 2 2 0 1 2 1 0 1 Sample Output 1 HINT 对于100%的数据满足N,M<=200,0<=L<=R<=1000,0<=Aij<=1000 题解:容易想到二分,并且这个和式可以拆成$\sum A_{ij}-\sum B_

ZOJ 2314 有上下界的网络流

点击打开链接 题意:给定m条边和n个节点,每条边最少的流量和最多的流量,保证每个节点的出入流量和相等,问可以形成吗,可以则输出每条边的流量 思路:一道有上下界的网络流,因为有下界,说明我们每条边必须跑大于等于下界的流量,那我们可以转化一下,将下界设为必要边,也就是我们肯定会跑的边,而且这道题是没有源点和汇点的,所以我们要加这两个点,而对于一条边,a,b,low,high,我们a->b连的流量为high-low,a->T为low,S->b为low,跑最大流,如果满流则方案成功,找边的流量输

bzoj 2406 二分+有源有汇上下界网络流可行流判定

弱爆了,典型的行列建模方式,居然想不到,题做少了,总结少了...... 二分答案mid s----------------------->i行----------------------->j列----------------------------->t [si-mid,si+mid]                  [L,R]                 [s[j]-mid,s[j]+mid] 即对每一行建一个点,每一列建一个点,用边来表示某一行某一列上的东西. 这种建模方式一

sgu 194 上下界网络流可行流判定+输出可行流

1 #include <cstdio> 2 #include <cstring> 3 #define min(a,b) ((a)<(b)?(a):(b)) 4 #define oo 0x3f3f3f3f 5 #define N 210 6 #define M 100010 7 8 struct Dinic { 9 int n, src, dst; 10 int head[N], dest[M], flow[M], eid[M], next[M], etot; 11 int c

有上下界的网络流3-有源汇带上下界最小流SGU176

题目大意:有一个类似于工业加工生产的机器,起点为1终点为n,中间生产环节有货物加工数量限制,输入u v z c, 当c等于1时表示这个加工的环节必须对纽带上的货物全部加工(即上下界都为z),c等于0表示加工上界限制为z,下界为0,求节点1(起点)最少需要投放多少货物才能传送带正常工作. 解题思路:    1.直接 增设超级源点ss和超级汇点tt并连上附加边,对 当前图 求 无源汇带上下界可行流    2.将图的汇点sd连一条容量无限制的边到图的源点st,再求一遍 无源汇带上下界可行流    3.

有上下界的网络流2-有源汇带上下界网络流ZOJ3229

ZOJ3229题目大意:一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝可以和C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照:否则输出-1. 解题思路:        1.增设一源点st,汇点sd,st到第i天连一条上界为Di下界为0的边,每个女神到汇点连一条下界为Gi上界为正无穷的边,对于每一天,当天到第i个女孩连一条[Li,Ri]的边.        2.

ZOJ 3229 有上下界最大流

1: /** 2: ZOJ 3229 有上下界的最大流 3: 两次求最大流的过程,非二分 4: 有源汇上下界的最大流问题, 首先连接 sink -> src, [0,INF]. 5: 根据net的正负,来建立 Supersrc 与 supersink 之间的边,做一次 maxflow. 6: 若所有的Supersrc 与 Supersink满流,则说明存在可行流. 7: 然后删除 sink -> src之间的边.(cap 置零即可). 从src -> sink 做一次最大流. 8: 两次