kuangbin专题带你飞 十一网络流 hdu3416(最短路+最大流)

Marriage Match IV HDU - 3416

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

有n个城市。给你m条边。图为有向图。
问你每次都走最短路,且走过的边不再走。可以到几次终点。

思路:

最短路+网络流。
把最短路径上的边加入到网络流里。
之后跑一遍最大流

AC

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#define fi first
#define se second
#define sz(a) ((int)a.size())
#define pb push_back
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define eb emplace_back
#define mp make_pair
#define mst(x,a) memset(x,a,sizeof(x))
#define fzhead EDGE(int u, int v, int c, int f)
#define fzbody from(u), to(v), cap(c), flow(f)
using namespace std;
typedef pair<int,int>pa;
const int N=100+10;
const int maxn=1000+10;
const int maxm=1e5+10;
const int inf =0x3f3f3f3f;
struct EDGE{
    int from,to,cap,flow;
    EDGE(){}
    fzhead:fzbody{}
};
int head[maxn<<1], dis[maxn], vis[maxn];
int cnt,n,m,st,ed;
struct Dinic{
    int n,m,s,t;
    vector<EDGE> edges;
    vector<int> g[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
///cur就是记录当前循环到了哪一条边。
    void init(int n){
        this->n = n;
        for(int i=0; i<n; i++)g[i].clear();
        edges.clear();
    }
    void add(int from, int to, int cap){
       // edges.eb(from,to,cap,0);
        //edges.eb(to,from,0,0);
        edges.pb({from,to,cap,0});
        edges.pb({to,from,0,0});
        ///加边同时,加正向和反向。
        m=edges.size();
        g[from].pb(m-2);
        g[to].pb(m-1);
    }
    bool bfs(){
        mst(vis,0);
        mst(d,0);
        queue<int>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;///源点深度为1.
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=0; i<sz(g[x]); i++)
            {
                EDGE&e=edges[g[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];///当汇点的深度不存在时,说明不存在分层图。
    }
    int dfs(int x, int a){
        ///x为当前节点,a为流量。
        if(x==t || a==0)return a;///当已经到达汇点,或者流量不存在时,返回。
        int flow=0,f;
        for(int &i=cur[x]; i<sz(g[x]); i++){
///注意这里的“&”符号,这样i增加同时也能改变cur【x】的值,达到弧优化的目的。
            EDGE& e=edges[g[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){///判断并且增广。
                e.flow+=f;///加减
                edges[g[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int maxflow(int s, int t){
        this->s=s,this->t=t;
        int flow=0;
        while(bfs()){
///每一次建立分层图后,都要把cur置为每一个点的第一条边
            mst(cur,0);
        flow+=dfs(s,inf);
        }
        return flow;
    }
} dinic;
struct Edge{
    int to, v,next;
    Edge(){}
    Edge(int ed, int v, int nex):to(ed),v(v),next(nex){}
}e[maxm];
void add(int bg, int ed, int v)
{
    e[++cnt]=Edge(ed, v, head[bg]);
    head[bg]=cnt;
}
inline void dij(int s)
{
    mst(dis,0x3f);
    For(i, 1, n)vis[i]=0;
    priority_queue<pa>q;
    dis[s]=0;q.push(mp(0,s));
    while(!q.empty())
    {
        int u=q.top().se;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            if(dis[e[i].to]>dis[u]+e[i].v)
            {
                dis[e[i].to]=dis[u]+e[i].v;
                q.push(mp(-dis[e[i].to],e[i].to));
            }
        }
    }
}
void init(){cnt=0;mst(head,-1);}
//
int main()
{
    int t;scanf("%d", &t);
    while(t--){
        init();
        scanf("%d%d", &n, &m);
        int u,v,c;
        for(int i=1; i<=m; i++){
            scanf("%d%d%d",&u,&v,&c);
            if(u==v)continue;
            add(u,v,c);
        }
//        for(int i=1; i<=n; i++){
//            cout<<i<<"  i    ";
//            for(int j=head[i]; j!=-1; j=e[j].next)cout<<e[j].to<<' ';
//        cout<<endl;
     //   }
        scanf("%d%d", &st, &ed);
        dij(st);
       // for(int i=1; i<=n; i++)cout<<dis[i]<<' ';
      //  cout<<endl;
        dinic.init(maxn);
        for(int i=1; i<=n; i++){
            for(int j=head[i]; j!=-1; j=e[j].next){
                int v=e[j].to;
                if(dis[v]==dis[i]+e[j].v){
                    dinic.add(i,v,1);
                }
            }
        }
        printf("%d\n", dinic.maxflow(st,ed));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值