sgu Flow construction

Flow construction

题目:

给出N个节点M条水管,要求在满足上下界的情况下。满足起点最小的流量。

算法:

这是最小流????不知道。只知道用求解上下界最大流的方法就过了。

做这题收获了很多东西。知道了同一点的flow是真实的流量值,虽然以前在书上或论文中看到过,不过印象不深,但是经过这题深刻的懂了。就是这题输出的时候有点麻烦。。。要记录每次的路径,然后用我刚才说的那个,同一个点的flow是真实的流量值!!!!

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;

const int INF = 1 << 28;
const int MAXN = 200 + 10;
///////////////////////////////////////

//上下界最小流

struct Edge{
    int from,to,cap,flow,cost;
    Edge(){};
    Edge(int _from,int _to,int _cap,int _flow)
        :from(_from),to(_to),cap(_cap),flow(_flow){};
};
vector<Edge> edges;
vector<int> G[MAXN];
int cur[MAXN],d[MAXN];
bool vst[MAXN];
int N,M,src,sink;

////////////////////////////////

//上下界网络流
int sum;
int in[MAXN],id[MAXN*MAXN],low[MAXN*MAXN];

void init(){
    src = N + 2; sink = src + 1;
    for(int i = 0;i <= sink;++i)
        G[i].clear();
    edges.clear();
}

void addEdge(int from,int to,int cap){
    edges.push_back(Edge(from,to,cap,0));
    edges.push_back(Edge(to,from,0,0));
    int sz = edges.size();
    G[from].push_back(sz - 2);
    G[to].push_back(sz - 1);
}

bool BFS(){
    memset(vst,0,sizeof(vst));
    queue<int> Q;
    vst[src] = 1;
    d[src] = 0;
    Q.push(src);

    while(!Q.empty()){
        int x = Q.front(); Q.pop();
        for(int i = 0;i < (int)G[x].size();++i){
            Edge& e = edges[G[x][i]];
            if(!vst[e.to] && e.cap > e.flow){
                vst[e.to] = 1;
                d[e.to] = d[x] + 1;
                Q.push(e.to);
            }
        }
    }

    return vst[sink];
}

int DFS(int x,int a){
    if(x == sink||a == 0)
        return a;

    int flow = 0,f;
    for(int& i = cur[x];i < (int)G[x].size();++i){
        Edge& e = edges[G[x][i]];
        if(d[e.to] == d[x] + 1&&(f = DFS(e.to,min(a,e.cap - e.flow))) > 0){
            e.flow += f;
            edges[G[x][i]^1].flow -= f;
            flow += f;
            a -= f;
            if(a == 0) break;
        }
    }
    return flow;
}

int maxFlow(){
   int flow = 0;
   while(BFS()){
       memset(cur,0,sizeof(cur));
       flow += DFS(src,INF);
   }
   return flow;
}

void solve(){
   for(int i = 1;i <= N;++i){
       if(in[i] > 0){
          sum += in[i];
          addEdge(src,i,in[i]);
       } else {
          addEdge(i,sink,-in[i]);
       }
   }

   sum -= maxFlow();
   addEdge(N,1,INF);   //是图变成无源无汇
   int flow = maxFlow();

   if(flow != sum){
       puts("Impossible");
       return;
   }

   int sz = edges.size();    //N --> 1 的容量
   printf("%d\n",edges[sz - 2].flow);  //反向弧的流量,即为正向真实流的流量!!!
   for(int i = 0;i < M;++i){
      if(low[i] > 0)
         printf("%d%c",low[i],i == M - 1 ? '\n':' ');
      else
         printf("%d%c",edges[id[i]].flow,i == M - 1 ? '\n':' ');
   }

}

int main()
{
    while(scanf("%d%d",&N,&M) == 2){
        init();
        int x,y,c,d;
        sum = 0;
        memset(in,0,sizeof(in));

        for(int i = 0; i < M;++i){
            scanf("%d%d%d%d",&x,&y,&c,&d);
            if(d == 0){              //流量没限制
               id[i] = edges.size();
               addEdge(x,y,c);

            } else {
               //sum += c;
               in[x] -= c;
               in[y] += c;
               low[i] = c;
              // addEdge(src,y,c);
               //id[i] = edges.size();   //反向弧的流量,即为正向真实流的流量!!!
               //addEdge(x,sink,c);
            }
        }

        solve();
    }
    return 0;
}
时间: 2024-10-09 13:13:22

sgu Flow construction的相关文章

Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法

/** 题目:Flow construction SGU - 176 链接:https://vjudge.net/problem/SGU-176 题意: 有源汇有上下界的最小流. 给定n个点,m个管道.每个管道给出u,v,z,c.u表示起点,v表示终点,z表示容量,如果c==1,那么表示还有下界为z. 如果c==0,表示没有下界. 求从1到n的最小流. 思路: 第一种做法: 转化为无源汇求超级源S到超级汇T的最大流flow1(此时从s出发的流和为flow1),然后讲t到s的边删掉(可以使流量等于

【SGU 176】 Flow construction

176. Flow construction time limit per test: 0.5 sec. memory limit per test: 4096 KB input: standard output: standard You have given the net consisting of nodes and pipes; pipes connect the nodes. Some substance can flow by pipes, and flow speed in an

SGU 176.Flow construction

时间限制:0.5s 空间限制:4M 题意: 有一个由管道组成的网络,有n个节点(n不大于100),1号节点可以制造原料,最后汇集到n号节点.原料通过管道运输.其中有一些节点有管道连接,这些管道都有着最大的流量限制,其中有一些管道必须充满.求1号节点最小的制造原料速度.如果原料不能运输到n,输出“Impossible” Solution 第一道有上下界的网络流.从理解不太深刻,wa了很多次后.完全理解了有上下界网络流的算法. 首先,要构造一个伴随网络,由此判断,是否能让所有的下界满足,并连通源汇点

sgu 176 Flow construction(有源汇的上下界最小流)

[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足流量平衡的最小流量. [思路] 按照可行流构造网络.不连t->s的边先跑一遍附加源汇点的最大流,然后连t->s一条inf边,在残量网络上跑一遍最大流.第一次求最大流所以能走的边都已经流满,第二次求附加源汇点最大流t->s的流量就会尽可能小. 另外还可以二分下界mid,然后连边(T,S,mid

sgu176 Flow Construction【有源汇有上下界最小流】

同样是模板题. 首先将有源汇转换为无源汇,假设原来的源汇为st,我们加入的源汇为ST,那么我们应该从t到s连一条流量为+∞的边,使原来的st满足收支平衡,退化为普通节点. 分离必要边和其他边,从S到T跑最大流,所有与源或者汇相连的边都流满则证明有解. 去掉t到s容量为+∞的边,去掉必要边,从t到s跑最大流. 把得到的答案相减即可. 如果我们得到的答案是负的,那么说明它内部t到s连成了环,那么我们加上S到s容量为-ans的边,跑S到t的最大流,这样所有的边的流量应该就是0,再加上流量下界即为答案.

sgu100~199题解

老东西了..发上来吧.. Sgu题解系列  南开中学邹事成 100:A+B略 101:Domino 给n块多米诺骨牌,每张骨牌两端各有从1到6的一个数字,现在要把这些骨牌排成一列,使相邻的两块骨牌相对的面所写的数字一样. 可以把每一块多米诺骨牌想象成一条边,把面上写的数字抽象成点,比如一块骨牌正面写的1反面写的2就想象成连了一条从1到2的边,那么这就是求一条有重边的欧拉回路了,dfs一下即可. 102:Coprimes给定n求从1到n中与n互质的数的个数. 可以把n质因数分解后直接代入欧拉函数.

网络流专栏

最大流 POJ 1273 Drainage Ditches POJ 1274 The Perfect Stall (二分图匹配) POJ 1698 Alice's Chance(构图) POJ 1459 Power Network(构图) POJ 2112 Optimal Milking (二分) POJ 2455 Secret Milking Machine (二分) POJ 3189 Steady Cow Assignment (枚举) POJ 1637 Sightseeing tour (

Soj题目分类

-----------------------------最优化问题------------------------------------- ----------------------常规动态规划  SOJ1162 I-Keyboard  SOJ1685 Chopsticks SOJ1679 Gangsters SOJ2096 Maximum Submatrix  SOJ2111 littleken bg SOJ2142 Cow Exhibition  SOJ2505 The County

网络流柱

最大流量 POJ 1273 Drainage Ditches POJ 1274 The Perfect Stall (二分图匹配) POJ 1698 Alice's Chance(构图) POJ 1459 Power Network(构图) POJ 2112 Optimal Milking (二分) POJ 2455 Secret Milking Machine (二分) POJ 3189 Steady Cow Assignment (枚举) POJ 1637 Sightseeing tour