VOJ - Avoiding the Apocalypse (最大流—时间拆点)

Avoiding the Apocalypse

题目链接: Avoiding the Apocalypse Gym - 101512A

题意

有n个点,开始i点上有g个人,每条路是a通向b,花费t秒,每秒可以通过t人,有m个终点,问在s秒内最多多少人到达终点


思路

因为单向边的有向性,与时间的有向性相呼应,所以我们可以将其拆点,将时间转换成空间,这题的时间和点数都挺少的,所以,我们用空间来换时间完全可以。

注意在开始状态时,一定要将每个点扩充。最后跑一下最大流即可。


代码

#include <bits/stdc++.h>
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)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back

typedef double db;
typedef long long ll;
const int MAXN = (int)5e5+7;
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 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*105) G[i].clear();
}

int main()
{
    int T,n,ini,g,step,m;
    int sp,tp;
    scanf("%d",&T);
    while (T --) {
        scanf("%d %d %d %d",&n,&ini,&g,&step);
        sp = (n+1)*105+1;tp = sp+1;N = n+2;
        init();
        add_edge(sp,ini*105,g);
        for (int i = 1;i <= n;i ++) {
            for (int j = 0;j < step;j ++) {
                add_edge(i*105+j,i*105+j+1,g); //t0 -> T-t0
            }
        }
        scanf("%d",&m);

        for (int i = 0;i < m;i ++) {
            int x;
            scanf("%d",&x);
            add_edge(x*105+step,tp,g);
        }

        int r;
        scanf("%d",&r);
        for (int i = 0;i < r;i ++) {
            int a,b,p,t;
            scanf("%d %d %d %d",&a,&b,&p,&t);
            for (int j = 0;j+t <= step;j ++){
                add_edge(a*105+j,b*105+j+t,p);
            }
        }
        int ans = max_flow(sp,tp);
        printf("%d\n",ans);
    }
}   

猜你喜欢

转载自blog.csdn.net/qq_40513946/article/details/81352471