SGU 194 无源无汇上下界网络流

来源:互联网 发布:淘宝卖家订单能删除吗 编辑:程序博客网 时间:2024/05/21 10:56

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=194

题意:

n 个点 m条有向边

u v l r 代表该边的流量区间为 [l,r]

若存在最大流则输出每条边的流量

若不存在则输出NO

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<queue>#include<vector>using namespace std;#define ll int #define N 10004#define M 105000#define inf 1073741824#define inf64 1152921504606846976struct Edge{  ll from, to, cap, nex, max;  }edge[M*4];//注意这个一定要够大 不然会re 还有反向弧  ll head[N], edgenum;  void add(ll u, ll v, ll cap){  Edge E = { u, v, cap, head[u],cap};  edge[ edgenum ] = E;  head[u] = edgenum ++;  Edge E2= { v, u, 0,   head[v],cap};  edge[ edgenum ] = E2;  head[v] = edgenum ++;  }  ll sign[N];  bool BFS(ll from, ll to){  memset(sign, -1, sizeof(sign));  sign[from] = 0;  queue<ll>q;  q.push(from);  while( !q.empty() ){  int u = q.front(); q.pop();  for(ll i = head[u]; i!=-1; i = edge[i].nex)  {  ll v = edge[i].to;  if(sign[v]==-1 && edge[i].cap)  {  sign[v] = sign[u] + 1, q.push(v);  if(sign[to] != -1)return true;  }  }  }  return false;  }  ll Stack[N], top, cur[N];  ll dinic(ll from, ll to){  ll ans = 0;  while( BFS(from, to) )  {  memcpy(cur, head, sizeof(head));  ll u = from;      top = 0;  while(1)  {  if(u == to)  {  ll flow = inf, loc;//loc 表示 Stack 中 cap 最小的边  for(ll i = 0; i < top; i++)  if(flow > edge[ Stack[i] ].cap)  {  flow = edge[Stack[i]].cap;  loc = i;  }  for(ll i = 0; i < top; i++)  {  edge[ Stack[i] ].cap -= flow;  edge[Stack[i]^1].cap += flow;  }  ans += flow;  top = loc;  u = edge[Stack[top]].from;  }  for(ll i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标  if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;  if(cur[u] != -1)  {  Stack[top++] = cur[u];  u = edge[ cur[u] ].to;  }  else  {  if( top == 0 )break;  sign[u] = -1;  u = edge[ Stack[--top] ].from;  }  }  }  return ans;  }  void init(){memset(head,-1,sizeof head);edgenum = 0;}ll n, m;ll in[N], out[N], b[M];int main(){ll u, v, maxx, i, j;scanf("%d %d",&n, &m);init();for(i = 0; i <= n+1; i++)in[i] = out[i] = 0;ll from = 0, to = n+1;for(i = 0; i < m; i++){scanf("%d %d %d %d",&u,&v,&b[i],&maxx);add(u,v,maxx-b[i]);in[v] += b[i];out[u]+= b[i];}for(i = 1; i <= n; i++){if(in[i] > out[i])add(from, i, in[i]-out[i]);else add(i, to, out[i]-in[i]);}dinic(from, to);bool yes = true;  //源点的出边必须满流  for(i = head[from]; ~i; i = edge[i].nex) if(edge[i].cap)yes = false;  //限制要相同  if(yes == false){puts("NO");return 0;}  else puts("YES");  for(i = 0; i < m; i++){  ll ans = b[i] + (edge[i*2].max - edge[i*2].cap);  printf("%lld\n",ans);  }  return 0;}/*4 6 1 2 1 2 2 3 1 2 3 4 1 2 4 1 1 2 1 3 1 2 4 2 1 2 4 6 1 2 1 3 2 3 1 3 3 4 1 3 4 1 1 3 1 3 1 3 4 2 1 3 */


#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<vector>#include<queue>using namespace std;#define ll long long #define inf 123456789123456#define MAXN N#define N 1000 #define M 100000//N为点数 M为边数inline ll Min(ll a,ll b){return a>b?b:a;} //注意这个类型是intstruct Edge{ll from, to, cap, nex, max;}edge[M*2];//双向边,注意RE 注意这个模版是 相同起末点的边 同时有效而不是去重ll head[N],edgenum;//2个要初始化-1和0void add(ll u, ll v, ll cap){//网络流要加反向弧,即u->v 为10 则 v->u为 -10Edge E = {u, v, cap, head[u],cap};edge[ edgenum ] = E;head[ u ] = edgenum++;Edge E2 = {v, u, 0,  head[v],cap}; //这里的cap若是单向边要为0edge[ edgenum ] = E2;head[ v ] = edgenum++;}ll dis[N], cur[N];//dis[i]表示i点距离起点的距离 cur[i]表示i点所连接的边中 正在考虑的边 优化不再考虑已经用过的点 初始化为headbool vis[N];bool BFS(ll Start,ll End){//跑一遍最短路memset(vis,0,sizeof(vis)); memset(dis,-1,sizeof(dis));queue<ll>Q;Q.push(Start);dis[Start]=0;vis[Start]=1;while(!Q.empty()){ll u = Q.front(); Q.pop();for(ll i = head[u]; i != -1; i = edge[i].nex){Edge E = edge[i];if( !vis[E.to] && E.cap > 0){vis[ E.to ] = true;dis[ E.to ] = dis[ u ] + 1;if(E.to == End) return true;Q.push( E.to );}}}return false;}ll DFS(ll x, ll a,ll End){//当前 流入x 的流量是a   流量a 是所有流过边中 边权的最小值if( x == End || a == 0)return a; ll flow = 0, f; //flow表示从x点流到下面所有点,最大的流量for(ll& i = cur[x]; i != -1; i = edge[i].nex){Edge& E = edge[i];if(dis[x] + 1 == dis[E.to] && (f = DFS(E.to , Min(a, E.cap), End))>0 ){E.cap -= f;edge[ i^1 ].cap += f;//反向边要减掉flow += f;a -= f;if(a==0)break;}}return flow;}ll Maxflow(ll Start,ll End){ll flow=0; while(BFS(Start,End)){ //当存在源点到汇点的路径时memcpy(cur,head,sizeof(head));//把head的数组复制过去flow += DFS(Start, inf, End);}return flow;}/**/void init(){memset(head,-1,sizeof head);edgenum = 0;}ll n, m;ll in[MAXN], out[MAXN], b[M];ll s, t;int main(){ll u, v, maxx, i, j;scanf("%lld %lld",&n, &m);init();for(i = 0; i <= n+1; i++)in[i] = out[i] = 0;ll from = 0, to = n+1;s = from, t = to;for(i = 0; i < m; i++){scanf("%lld %lld %lld %lld",&u,&v,&b[i],&maxx);add(u,v,maxx-b[i]);in[v] += b[i];out[u]+= b[i];}for(i = 1; i <= n; i++){if(in[i] > out[i])add(from, i, in[i]-out[i]);else add(i, to, out[i]-in[i]);}Maxflow(from, to);bool yes = true;//源点的出边必须满流for(i = head[from]; ~i; i = edge[i].nex) if(edge[i].cap)yes = false;//限制要相同if(yes == false){puts("NO");return 0;}else puts("YES");for(i = 0; i < m; i++){ll ans = b[i] + (edge[i*2].max - edge[i*2].cap);printf("%lld\n",ans);}return 0;}


0 0
原创粉丝点击