HDU 3416 Marriage Match IV【最短路 + 最大流】经典模型好题

传送门
题意: 给定一幅单向图(n, m), 起点和终点, 问起点到终点有所少条最短路径, 每条边只能做一遍.

思路: 如果没有只走一遍的限制, 那么就是个很简单的最短路了. 关键在于只能走一遍. 那么我们就想跑最短路吧图中有用的边先存下来, 重新建图, 让每条边的流量的为1, 然后跑s - t 的最大流就是ans. 有用的边为(假设dis1表示从s出发的最短路, dis2表示t出发的最短路.) 那么就是dis1[u] + w + dis2[v] = dis1[t], 然后就是上板子即可, 主要是这个模型很重要, 边只能经过一次那么我们就设流量为1, 那就是最大流. 这种模型才是本道题的精华所在.

AC Code

const int maxn = 1e3 + 5;
const int maxm = 1e5+5;
int head1[maxn], cnt1;
int n, m, s, t;
bool vis1[maxn];
int d[maxn], cur[maxn];
struct node1 {
    int u, v;
    int cap, flow, next;
} e[maxm*2]; //因为是双向边  所以记得开二倍

void init1() {
    cnt1 = 0;
    Fill(head1, -1);
}

void add1(int u, int v, int c, int f) {
    e[cnt1] = node1{u, v, c, f, head1[u]};
    head1[u] = cnt1++;
}

bool BFS() {
    queue<int> q; q.push(s);
    Fill(vis1,0); vis1[s] = 1;
    d[s] = 0;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int i = head1[u] ; ~i ; i = e[i].next) {
            int to = e[i].v;
            if (!vis1[to] && e[i].cap > e[i].flow) { //只考虑残量网络的弧
                vis1[to] = 1;
                d[to] = d[u] + 1;
                q.push(to);
            }
        }
    }
    return vis1[t];
}

int dfs(int x, int a) {
    if (x == t || a == 0) return a;
    int flow = 0, f;
    int &i = cur[x];
    for (i = head1[x] ; ~i ; i = e[i].next) { //从上次考虑的弧
        int to = e[i].v;
        if (d[to]== d[x] + 1 && (f = dfs(to, min(a, e[i].cap - e[i].flow))) > 0) {
            e[i].flow += f;
            e[i^1].flow -= f;
            flow += f;
            a -= f;
            if (a == 0) break;
        }
    }
    return flow;
}

int Dinic() {
    int maxflow = 0;
    while (BFS()) {
        Fill(cur, 0);
        maxflow += dfs(s, inf);
    }
    return maxflow;
}

struct node2 {
    int to, next, w;
    bool operator < (const node2 & a) const {
        return w > a.w;
    }
} g[maxm];
int cnt2 , head2[maxn];
void init2() {
    cnt2 = 0;
    Fill(head2, -1);
}
void add2(int u, int v, int w) {
    g[cnt2] = node2{v, head2[u], w};
    head2[u] = cnt2++;
}
int dis[2][maxn];
int vis2[maxn];
void dij(int st, int id)
{
    priority_queue q;
    Fill(dis[id],inf); Fill(vis2,0);
    dis[id][st] = 0;
    q.push((node2){st, 0, 0});
    while (!q.empty()) {
        node2 u = q.top();
        q.pop();
        if(vis2[u.to]) continue;
        vis2[u.to] = 1;
        for (int i = head2[u.to]; ~i ; i = g[i].next) {
            int to = g[i].to;
            if (dis[id][to] > dis[id][u.to] + g[i].w) {
                dis[id][to] = dis[id][u.to] + g[i].w;
                q.push((node2){to, 0, dis[id][to]});
            }
        }
    }
}
bool is[maxm];
struct gg {
    int u, v, w;
} pp[maxm];
void solve() {
    scanf("%d%d", &n, &m);
    init2(); Fill(is, false);
    for (int i = 1 ; i <= m ; i ++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add2(u, v, w);
        pp[i].u = u; pp[i].v = v; pp[i].w = w;
    }
    scanf("%d%d", &s, &t);
    dij(s, 0);
    init2();
    for (int i = 1 ; i <= m ; i ++) {
        add2(pp[i].v, pp[i].u, pp[i].w);
    }
    dij(t, 1);
    for (int i = 1 ; i <= m ; i ++) {
        int tmp = dis[0][pp[i].u];
        tmp += pp[i].w + dis[1][pp[i].v];
        if (tmp == dis[0][t]) is[i] = true;
    }
    init1();
    for (int i = 1 ; i <= m ; i ++) {
        if (!is[i]) continue;
        add1(pp[i].u, pp[i].v, 1, 0);
        add1(pp[i].v, pp[i].u, 0, 0);
    }
    printf("%d\n", Dinic());
}

你可能感兴趣的:(最短路相关,网络流)