Gym - 101908L - Subway Lines (二分+Dinic)

Subway Lines

题目链接: Subway Lines Gym - 101908L

题意

给你R个炼油厂,P个加油站,现在,每个炼油厂有着各自的储油量,每个加油站都有着需要的油量。现在给出一些匹配方路线,每条路线无油量运输限制,但跑一边路程会需要花费一定量的时间,问能否满足所有的加油站油量需要,如果可以满足,最少用多少时间?

数据范围: R , P < 1 0 3 R,P<10^3 R,P<103


思路

这题一看,如此分配问题,必定是用网络流没跑了,

但怎么建边呢,原先我想到是跑最小费用最大流,费用优先,但是细想一下,这个原理不同,最小费用最大流需要的是单位流量费用,而这里忽略了单位流量。

于是,我就在费用流的路上渐行渐远了。。。。。

其实,应该用普通的最大流,每次二分建边即可。


代码

#include 
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back

typedef double db;
typedef long long ll;
const int MAXN = (int)2e4+2007;
const int INF = (int)0x3f3f3f3f;

// 用于表示表示边的结构体(终点、容量、反向边)
struct edge{
    int to,cap,rev;
    edge(int to = 0,int cap = 0,int rev = 0):to(to),cap(cap),rev(rev){}
};

int SumOut;
int N,M;
vector<edge> G[MAXN];
int level[MAXN]; //顶点到源点的距离标号
int iter[MAXN];  //当前弧,在其之前的边已经没有用了

//向图中增加一条从s到t容量为cap的边
void add_edge(int from,int to,int cap) {
    G[from].pb(edge(to,cap,G[to].size()));
    G[to  ].pb(edge(from,0,G[from].size()-1));
}

//通过BFS计算从源点出发的距离标号
void bfs(int s){
    mmm(level,-1);
    queue<int> qu;
    level[s] = 0;
    qu.push(s);
    while (!qu.empty()) {
        int v = qu.front(); qu.pop();
        rep(i,0,G[v].size()-1) {
            edge &e = G[v][i];
            if (e.cap > 0 && level[e.to] < 0) {
                level[e.to] = level[v] + 1;
                qu.push(e.to);
            }
        }
    }
}

//通过DFS寻找增广路
int dfs(int v,int t,int f) {
    if (v == t) return f;
    for (int &i = iter[v];i < G[v].size();i ++) {
        edge &e = G[v][i];
        if (e.cap > 0 && level[v] < level[e.to]) {
            int d = dfs(e.to,t,min(f,e.cap));
            if (d > 0) {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

//求解从s到t的最大流
int max_flow(int s,int t){
    int flow = 0;
    for (;;) {
        bfs(s);
        if (level[t] < 0) return flow;
        mmm(iter,0);
        int f;
        while ((f = dfs(s,t,INF)) > 0)
            flow += f;
    }
}

void init(){
    rep(i,1,N) G[i].clear();
}

int P,R;
int in[MAXN];
int out[MAXN];
struct Node{
    int u,v,cost;
    Node(int u = 0,int v = 0,int cost = 0):u(u),v(v),cost(cost){}
};
Node tmp[MAXN];

int s,t;
bool OK(int m) {
    init();
    rep(i,1,M) {
        if (tmp[i].cost <= m) add_edge(tmp[i].u,tmp[i].v,INF);
    }
    rep(i,M+1,R+P+M) {
        add_edge(tmp[i].u,tmp[i].v,tmp[i].cost);
    }
    int res = max_flow(s,t);
    return res == SumOut;
}

int main()
{
    scanf("%d %d %d",&P,&R,&M);
    rep(i,1,P) {
        scanf("%d",&out[i]);
        SumOut += out[i];
    }
    rep(i,1,R) scanf("%d",&in[i]);
    N = P+R;
    s = ++N;
    t = ++N;

    rep(i,1,M) {
        int x,y,w;
        scanf("%d %d %d",&x,&y,&w);
        tmp[i] = Node(y,x+R,w);
    }
    rep(i,1,R) {
        tmp[i+M] = Node(s,i,in[i]);
    }
    rep(i,1,P) {
        tmp[i+M+R] = Node(i+R,t,out[i]);
    }
    int l = 0,r = INF;
    while (l <= r) {
        int m = l+r>>1;
        if (OK(m)) r = m-1;
        else       l = m+1;
    }
    if (l != INF+1)    printf("%d\n",l);
    else               printf("-1\n");
}

你可能感兴趣的:(NetworkFlow)