【最短路+最大流】上学路线@安徽OI2006

【最短路+最大流】上学路线@安徽OI2006

PROBLEM

洛谷P4300

SOLUTION

先在原图上跑单源最短路,找出包含所有最短路径的子图。
要使从S到T的最短路变长,那么在子图中S到T不再连通,要求代价最小,即在子图上找最小割。
因为“最小割等于最大流“,所以在子图上跑一遍最大流。
自己犯蠢,最短路子图建的双向边,wa了好几发

CODE

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 505;
const int MAXE = 124755*2;
const ll INF = 1247550005;
int n,m;
 
struct data {
    int u,v,t,c;
} da[MAXE*2];
 
struct Graph1 {
    struct edge {
        int v,t,nex;
    } ed[MAXE];
    int head[MAXN],tot;
    void addedge(int u,int v,int t) {
        tot++;
        ed[tot].v = v;
        ed[tot].t = t;
        ed[tot].nex = head[u];
        head[u] = tot;
    }
    ll d[MAXN];int p[MAXN];
    bool vis[MAXN];
    priority_queue<pair<ll,int> >q;
    void dijkstra(int st) {
        fill(d,d+n+1,INF);
        memset(vis,0,sizeof vis);
        d[st] = 0;
        q.push({0,st});
        while(q.size()) {
            int x = q.top().second;
            q.pop();
            if(vis[x])
                continue;
            vis[x] = 1;
            for(int i = head[x]; i; i=ed[i].nex) {
                int y = ed[i].v,z = ed[i].t;
                if(d[y]>d[x]+z) {
                    d[y] = d[x] + z;
                    q.push({-d[y],y});
                    p[y] = i;
                }
            }
        }
    }
    bool flag[MAXE];
    queue<int> q2;
    void bfs() {
        memset(flag,0,sizeof flag);
        memset(vis,0,sizeof vis);
        q2.push(n);
        while(q2.size()) {
            int x = q2.front();
            q2.pop();
            if(vis[x])
                continue;
            vis[x] = 1;
            int pre = p[x];
            for(int i = head[x]; i; i=ed[i].nex) {
                int y = ed[i].v,z = ed[i].t;
                if((i^1) == pre||d[y] + z == d[ed[pre^1].v] + ed[pre^1].t) {
                    flag[i^1] = 1;
                    q2.push(y);
                }
            }
        }
    }
} G1;
 
struct Graph2 {
    int head[MAXN],ver[MAXE<<1],Next[MAXE<<1],d[MAXN];
    int s,t,tot;
    ll maxflow,edge[MAXE<<1];
    queue<int> q;
    void add(int x,int y,int z) {
        ver[++tot] = y,edge[tot] = z,Next[tot] = head[x],head[x] = tot;
        ver[++tot] = x,edge[tot] = 0,Next[tot] = head[y],head[y] = tot;
    }
    bool bfs() {
        memset(d,0,sizeof d);
        while(q.size())
            q.pop();
        q.push(s);
        d[s] = 1;
        while(q.size()) {
            int x = q.front();
            q.pop();
            for(int i = head[x]; i; i=Next[i])
                if(edge[i]&&!d[ver[i]]) {
                    q.push(ver[i]);
                    d[ver[i]] = d[x] + 1;
                    if(ver[i]==t)
                        return 1;
                }
        }
        return 0;
    }
    ll dinic(int x,ll flow) {
        if(x==t)
            return flow;
        ll rest = flow,k;
        for(int i = head[x]; i && rest; i=Next[i])
            if(edge[i]&&d[ver[i]] == d[x] + 1) {
                k = dinic(ver[i],min(rest,(ll)edge[i]));
                if(!k)
                    d[ver[i]] = 0;
                edge[i] -= k;
                edge[i^1] += k;
                rest-=k;
            }
        return flow - rest;
    }
} G2;
 
int main() {
    scanf("%d%d",&n,&m);
    G1.tot = 1;
    for(int i=1; i<=m; i++) {
        int u,v,t,c;
        scanf("%d%d%d%d",&u,&v,&t,&c);
        da[i*2] = {u,v,t,c};
        da[i*2+1] = {v,u,t,c};
        G1.addedge(u,v,t);
        G1.addedge(v,u,t);
    }
    G1.dijkstra(1);
    G1.bfs();
    G2.s = 1;
    G2.t = n;
    G2.tot = 1;
    for(int i=2; i<=G1.tot; i++) {
        if(G1.flag[i]) {
            int x = da[i].u,y = da[i].v,c = da[i].c;
            G2.add(x,y,c);
        }
    }
    ll flow = 0;
    while(G2.bfs())
        while(flow=G2.dinic(G2.s,INF))
            G2.maxflow += flow;
    cout<<G1.d[n]<<endl;
    cout<<G2.maxflow<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/NeilThang/p/9982041.html