HDU 3416 Marriage Match IV (最短路建图+最大流)

(点击此处查看原题)

题目分析

题意:给出一个有n个结点,m条单向边的有向图,问从源点s到汇点t的不重合的最短路有多少条,所谓不重复,意思是任意两条最短路径都不共用一条边,而且任意两点之间的边只会用一条。

思路:没有看出是最大流的话,可能会止步于用dijkstra得到所有的所有最短路包含的边,但是无法确定最多有多少条路。

但是学过网络流的人走到这一步就会想到这里需要用最大流求解:我们将每一条最短路上的边构成新的图,这个图中的边的边权都是1,在这个由最短路中的边组成的图中,求得的s-t最大流即为我们所求的答案。

代码区

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>

#define bug cout << "**********" << endl
#define show(x, y) cout<<"["<<x<<","<<y<<"] "
#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
const int Max = 1e5 + 10;
const int Max2 = 1e3+10;

struct Edge
{
    int to,next,flow;
}edge1[Max<<1],edge2[Max<<1],edge[Max<<1];

int T, n, m, s, t;
int head1[Max2],tot1;
int head2[Max2],tot2;
int dis_s[Max2],dis_t[Max2];      //某结点距离源点和始点的最近距离
bool vis[Max2];
int head[Max2],tot;
int dis[Max];

void init()
{
    memset(head1,-1,sizeof(head1));tot1 = 0;
    memset(head2,-1,sizeof(head2));tot2 = 0;
    memset(head,-1,sizeof(head));tot = 0;
    memset(dis_s,inf,sizeof(dis_s));
    memset(dis_t,inf,sizeof(dis_t));
}

void add1(int u, int v,int dist)             //原图的边
{
    edge1[tot1].to = v;
    edge1[tot1].flow = dist;
    edge1[tot1].next = head1[u];
    head1[u] = tot1++;

    edge2[tot2].to = u;
    edge2[tot2].flow = dist;
    edge2[tot2].next = head2[v];
    head2[v] = tot2++;
}



void add2(int u,int v,int flow)     //跑最大流的图
{
    edge[tot].to = v;
    edge[tot].flow = flow;
    edge[tot].next = head[u];
    head[u] = tot++;
}


void dfs_s()
{
    priority_queue<pair<int,int> > q;
    memset(vis,0,sizeof(vis));

    q.push(make_pair(0,s));
    dis_s[s] = 0;

    while(!q.empty())
    {
        int u = q.top().second;q.pop();
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = head1[u] ;i != -1;i = edge1[i].next)
        {
            int v = edge1[i].to;
            if(!vis[v] && dis_s[v] > dis_s[u] + edge1[i].flow)   //这里的flow就是边权,和网络流的图公用一个结构体
            {
                dis_s[v] = dis_s[u] + edge1[i].flow;
                q.push(make_pair(-dis_s[v],v));
            }
        }
    }
}

void dfs_t()
{
    priority_queue<pair<int,int> > q;
    memset(vis,0,sizeof(vis));

    q.push(make_pair(0,t));
    dis_t[t] = 0;

    while(!q.empty())
    {
        int u = q.top().second;q.pop();
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = head2[u] ;i != -1;i = edge2[i].next)
        {
            int v = edge2[i].to;
            if(!vis[v] && dis_t[v] > dis_t[u] + edge2[i].flow)   //这里的flow就是边权,和网络流的图公用一个结构体
            {
                dis_t[v] = dis_t[u] + edge2[i].flow;
                q.push(make_pair(-dis_t[v],v));
            }
        }
    }
}

bool bfs()
{
    memset(dis,-1,sizeof(dis));
    queue<int>q;
    q.push(s);dis[s] = 0;
    while(!q.empty())
    {
        int u = q.front();q.pop();
        for(int i = head[u]; i != -1 ; i  = edge[i].next)
        {
            int v = edge[i].to;
            if(edge[i].flow > 0 && dis[v] == -1)
            {
                dis[v] = dis[u] + 1;
                if(v == t) return true;
                q.push(v);
            }
        }
    }
    return false;
}

int dfs(int u, int flow_in)
{
    if(u == t) return flow_in;
    int flow_out = 0;
    for(int i = head[u] ; i != -1; i = edge[i].next)
    {
        int v= edge[i].to;
        if(edge[i].flow > 0 && dis[v] == dis[u] + 1)
        {
            int flow = dfs(v,min(flow_in,edge[i].flow));
            if(flow == 0) continue;
            flow_in -= flow;
            flow_out += flow;
            edge[i].flow -= flow;
            edge[i^1].flow += flow;
            if(flow_in == 0) break;
        }
    }
    return flow_out;
}

int Dinic()
{
    int sum = 0;
    while(bfs())
    {
        sum += dfs(s,inf);
    }
    return sum;
}

int main()
{
#ifdef LOCAL
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i = 1, u, v, dis;i <= m; i ++)
        {
            scanf("%d%d%d",&u,&v,&dis);
            if(u != v)
                add1(u,v,dis);
        }
        scanf("%d%d",&s,&t);
        dfs_s();
        dfs_t();

        for(int u = 1;u <= n ;u ++)
        {
            for(int i =head1[u]; i != -1; i =edge1[i].next)
            {
                int v = edge1[i].to;
                int flow = edge1[i].flow;
                if(dis_s[u] + dis_t[v] + flow == dis_s[t])  //这条边为最短路上的边
                {
                    add2(u,v,1);add2(v,u,0);
                }
            }
        }
        printf("%d
",Dinic());
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/winter-bamboo/p/11370566.html