Marriage Match IV---hdu3416(spfa + Dinic)

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=3416

有一个有向图,n个点,m条边,给一个起点和终点,求出从起点到终点的最短路共有几条,每条路只能走一次,每个点可以走多次;

先用spfa求出从起点到各点的距离dist,然后根据dist的值建立新的图,边权为1,套用Dinic模板求起点到终点的最大流即可;

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <string>
typedef long long LL;
#define INF 0x3f3f3f3f
#define met(a, b) memset(a, b, sizeof(a))
#define N 200005

using namespace std;

struct node
{
    int v, w, Next;
}G[N], e[N];



int n, m, dist[N], vis[N], A, B;
int l[N];

int Head[N], cnt;
void Add(int u, int v, int w)
{
    G[cnt].v = v;
    G[cnt].w = w;
    G[cnt].Next = Head[u];
    Head[u] = cnt++;
}

int Head1[N], cnt1;
void Add1(int u, int v, int w)
{
    e[cnt1].v = v;
    e[cnt1].w = w;
    e[cnt1].Next = Head1[u];
    Head1[u] = cnt1++;
}

void spfa()
{
    for(int i=1; i<=n; i++)
        dist[i] = INF;
    met(vis, 0);
    queue<int>Q;
    Q.push(A);
    vis[A] = 1;
    dist[A] = 0;
    while(!Q.empty())
    {
        int p = Q.front();Q.pop();
        vis[p] = 0;
        for(int i=Head[p]; i!=-1; i=G[i].Next)
        {
            int q = G[i].v;
            if(dist[q] > dist[p]+G[i].w)
            {
                dist[q] = dist[p]+G[i].w;
                if(!vis[q])
                {
                    vis[q] = 1;
                    Q.push(q);
                }
            }
        }
    }
}

bool bfs(int s, int End)
{
    met(l, 0);
    queue<int>Q;
    Q.push(s);
    l[s] = 1;
    while(!Q.empty())
    {
        int u = Q.front();Q.pop();
        if(u == End)return true;
        for(int i=Head1[u]; i!=-1; i=e[i].Next)
        {
            int v = e[i].v;
            if(!l[v] && e[i].w)
            {
                l[v] = l[u]+1;
                Q.push(v);
            }
        }
    }
    return false;
}

int dfs(int u, int MaxFlow, int End)
{
    if(u == End)return MaxFlow;

    int uflow = 0;

    for(int j=Head1[u]; j!=-1; j=e[j].Next)
    {
        int v = e[j].v;
        if(l[v]==l[u]+1 && e[j].w)
        {
            int flow = min(e[j].w, MaxFlow-uflow);
            flow = dfs(v, flow, End);
            e[j].w -= flow;
            e[j^1].w += flow;
            uflow += flow;
            if(uflow == MaxFlow)
                break;
        }
    }
    if(uflow == 0)
        l[u] = 0;
    return uflow;
}

int Dinic()
{
    int MaxFlow = 0;
    while(bfs(A, B))
        MaxFlow += dfs(A, INF, B);
    return MaxFlow;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        met(Head, -1);
        cnt = 0;
        met(Head1, -1);
        cnt1 = 0;

        scanf("%d %d", &n, &m);

        for(int i=1; i<=m; i++)
        {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            if(u == v)continue;
            Add(u, v, w);
        }
        scanf("%d %d", &A, &B);

        spfa();///更新dist;

        for(int i=1; i<=n; i++)
        {
            for(int j=Head[i]; j!=-1; j=G[j].Next)
            {
                int v = G[j].v;
                if(dist[v] == dist[i]+G[j].w)///建立新的网络流图;
                {
                    Add1(i, v, 1);
                    Add1(v, i, 0);
                }
            }
        }

        int ans = Dinic();///求最大流即可;

        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

posted @ 2016-09-01 14:47  西瓜不懂柠檬的酸  Views(249)  Comments(0Edit  收藏  举报
levels of contents