avatar
fireworks99
keep hungry keep foolish

HDU 3416 Marriage IV(the shortest path and maxflow)

Description

求最短路有几种方案

(不同的两种方案所经过的边完全不同!)

Analyze

以 A 为起点跑一遍spfa, 得到 dis_a[]

以 B 为起点跑一遍spfa, 得到 dis_b[]

对于边(u, v, w),若满足dis_a[u] + dis_b[v] + w == dis_a[B]

则这条边是最短路的可选边(可以作为最短路上的一条边)

找出所有的可选边,设其容量为1,A到B的最大流即完全不同的最短路方案数

结论:图论相关的题目,求有几种方案:将确定边设容量为1,求最大流即可

Code

#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define Begin cout << "Check Begin---------------\n";
#define END cout << "Check End-----------------\n";
#define Exit cout << "Exit---------------------\n";

const int INF = 0x3f3f3f3f;
const int N = int(1e3) + 5;
const int M = int(1e5) + 5;

int n, m, start, over;

int cnt_a, cnt_b, cnt_c;
struct edge
{
    int to, w, pre;
} a[M], b[M], c[2 * M];

int dis_a[N], dis_b[N];
bool vis_a[N], vis_b[N];
int head_a[N], head_b[N], head_c[N];

void init()
{
    cnt_a = 0, cnt_b = 0, cnt_c = 0;
    for(int i = 0; i <= n; ++i)
    {
        dis_a[i] = dis_b[i] = INF;
        vis_a[i] = vis_b[i] = 0;
        head_a[i] = head_b[i] = head_c[i] = -1;
    }
}

void add(int & cnt, edge * e, int * head, int from, int to, int w)
{
    e[cnt].to = to;
    e[cnt].w = w;
    e[cnt].pre = head[from];
    head[from] = cnt++;
}

void spfa(int s, int * head, edge * e, int * dis, bool * vis)
{
    queue<int> q;
    q.push(s);
    dis[s] = 0;
    vis[s] = 1;
    while(!q.empty())
    {
        int now = q.front();
        q.pop();
        vis[now] = 0;
        for(int i = head[now]; ~i; i = e[i].pre)
        {
            int to = e[i].to;
            if(dis[to] > dis[now] + e[i].w)
            {
                dis[to] = dis[now] + e[i].w;
                if(!vis[to])
                    q.push(to), vis[to] = 1;
            }
        }
    }
}

int maxflow, deep[N], cur[N];

bool BFS(int s, int t)
{
    memset(deep, INF, sizeof(deep));
    for(int i = 0; i <= n; ++i)
        cur[i] = head_c[i];

    deep[s] = 0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int now = q.front();
        q.pop();
        for(int i = head_c[now]; ~i; i = c[i].pre)
            if(deep[ c[i].to ] == INF && c[i].w)
            {
                deep[ c[i].to ] = deep[now] + 1;
                q.push(c[i].to);
            }
    }

    if(deep[t] < INF)
        return 1;
    return 0;
}

int DFS(int now, int t, int limit)
{
    if(!limit || now == t)
        return limit;

    int flow = 0, f;
    for(int i = cur[now]; ~i; i = c[i].pre)
    {
        cur[now] = i;///Try To Realize this sentence!!!
        if(deep[ c[i].to ] == deep[now] + 1)
            if(f = DFS(c[i].to, t, min(limit, c[i].w)))
            {
                flow += f;
                limit -= f;
                c[i].w -= f;
                c[i ^ 1].w += f;
                if(!limit)
                    break;
            }
    }
    return flow;
}

void Dinic(int s, int t)
{
    int tem;
    while(BFS(s, t))
        while(tem = DFS(s, t, INF))
            maxflow += tem;
}

int main()
{
    int _;
    scanf("%d", &_);
    while(_--)
    {
        scanf("%d %d", &n, &m);
        init();

        int u[M], v[M], w[M];
        for(int i = 1; i <= m ; ++i)
        {
            scanf("%d %d %d", &u[i], &v[i], &w[i]);
            if(u[i] == v[i])
                continue;
            add(cnt_a, a, head_a, u[i], v[i], w[i]);
            add(cnt_b, b, head_b, v[i], u[i], w[i]);
        }
        scanf("%d %d", &start, &over);

        spfa(start, head_a, a, dis_a, vis_a);
        spfa(over, head_b, b, dis_b, vis_b);

        for(int i = 1; i <= m; ++i)
            if(u[i] != v[i] && dis_a[ u[i] ] + dis_b[ v[i] ] + w[i] == dis_a[over])
            {
                add(cnt_c, c, head_c, u[i], v[i], 1);
                add(cnt_c, c, head_c, v[i], u[i], 0);
            }

        maxflow = 0;
        Dinic(start, over);
        cout << maxflow << '\n';
    }
    return 0;
}

注意形参里的引用与指针的合理使用!

Site by Baole Zhao | Powered by Hexo | theme PreciousJoy