zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    简单四则运算实现--第二次作业
    人生第一篇博客
    团队任务1:第一次团队会议
    第二次作业
    自我介绍
    五号团队—团队任务4:每日立会(2018-11-27)
    软件设计与开发准备
    原型设计与UI设计
    第一次团队会议
    课后作业2
  • 原文地址:https://www.cnblogs.com/winter-bamboo/p/11370566.html
Copyright © 2011-2022 走看看