• (最小割)Path


    http://acm.hdu.edu.cn/showproblem.php?pid=6582

    思路:找到最短路核心边建图,跑一遍最小割,最短路核心边的定义为设起点到每个点的最短距离为d[i],每个点到终点的最短路为d2[i],如果一条边起点为u,终点为v,边权为w,若d[u]+d2[v]+w==d[n]则这是一条最短路核心边。所以先用spfa求d[i],然后反向spfa求d2[i],最后建图dinic求出答案。

    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<queue>
    #include<cstdio>
    #include<stack>
    #include<cmath>
    #include<iostream>
    #define ll long long
    #define lowbit(x) x&(-x)
    using namespace std;
    const int maxn=20100;
    const int maxm=20100;
    const ll inf=1e18;
    struct node{
        int u,v,nxt;
        ll w;
    }e[2*maxm],e2[2*maxm],e3[2*maxm];
    int h[maxn],h2[maxn],h3[maxn],depth[maxn];
    ll d[maxn],d2[maxn];
    bool vis[maxn];
    int n,m,st,ed,cnt,cnt2,cnt3;
    void init()
    {
        memset(h,-1,sizeof(h));
        memset(h2,-1,sizeof(h2));
        memset(h3,-1,sizeof(h3));
        for(int i=0;i<=n;i++)
            d[i]=d2[i]=inf;
        cnt=cnt2=cnt3=0;
    }
    
    void add(int u,int v,ll w)//正向建边 
    {
        e[cnt].u=u,e[cnt].v=v,e[cnt].w=w;
        e[cnt].nxt=h[u];h[u]=cnt++;
    }
    
    void add2(int u,int v,ll w)//反向建边 
    {
        e2[cnt2].u=u,e2[cnt2].v=v,e2[cnt2].w=w;
        e2[cnt2].nxt=h2[u],h2[u]=cnt2++;
    }
    void add3(int u,int v,ll w)//重新建边 
    {
        e3[cnt3].u=u,e3[cnt3].v=v,e3[cnt3].w=w;
        e3[cnt3].nxt=h3[u],h3[u]=cnt3++;
    }
    
    bool spfa()//求每点到1的最短距离 
    {
        queue<int> q;
        memset(vis,0,sizeof(vis));
        d[st]=0;
        vis[st]=1;
        q.push(st);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=0;
            for(int i=h[u];i!=-1;i=e[i].nxt)
            {
                int v=e[i].v;
                ll  w=e[i].w;
                if(d[v]>d[u]+w)
                {
                    d[v]=d[u]+w;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return d[n]==inf;
    }
    
    void re_spfa()//求每点到n的最短距离 
    {
        queue<int> q;
        memset(vis,0,sizeof(vis));
        d2[ed]=0;
        vis[ed]=1;
        q.push(ed);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=0;
            for(int i=h2[u];i!=-1;i=e2[i].nxt)
            {
                int v=e2[i].v;
                ll  w=e2[i].w;
                if(d2[v]>d2[u]+w)
                {
                    d2[v]=d2[u]+w;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
      
    void create_map()//重新建边 
    {
        for(int i=0;i<cnt;i++)
        {
            int u=e[i].u;
            int v=e[i].v;
            ll  w=e[i].w;
            if((d[u]+d2[v]+w==d[ed])&&(d[u]<inf&&d2[v]<inf))
            {//最短路核心边 
                add3(u,v,w);
                add3(v,u,0); 
            }
        }
    }
    
    bool bfs(){//dinic分层 
        queue<int> que;
        memset(depth,0,sizeof(depth));
        que.push(st);
        depth[st]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            if(u==ed)
                return true;
            for(int i=h3[u];i!=-1;i=e3[i].nxt){
                int v=e3[i].v;
                ll  w=e3[i].w;
                if(!depth[v]&&w){
                    depth[v]=depth[u]+1;
                    que.push(v);
                }
            }
        }
        return false;
    }
    
    ll dfs(int u,ll dis)
    {
        if(u==ed)
            return dis;
        ll res=0;
        for(int i=h3[u];i!=-1;i=e3[i].nxt)
        {
            int v=e3[i].v;
            ll  w=e3[i].w;
            if((depth[v]==depth[u]+1)&&w)
            {
                ll di=dfs(v,min(w,dis-res));
                e3[i].w-=di;
                e3[i^1].w+=di;
                res+=di;
                if(res==dis)
                    return dis;
            }
        }
        return res;
    }
    
    void dinic()//dinic求最小割 
    {
        ll ans=0;
        while(bfs())
        {
            ans+=dfs(st,inf);
        }
        printf("%lld
    ",ans);
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            st=1,ed=n;
            init();
            for(int i=0;i<m;i++)
            {
                int u,v;ll w;
                scanf("%d%d%lld",&u,&v,&w);
                add(u,v,w);
                add2(v,u,w);
            }
            if(spfa())//特判,没有最短路 
                printf("0
    ");
            else
            {
                re_spfa();
                create_map();
                dinic();
            }    
        }
        return 0;
    }
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 进制转换
    数据备份服务商Rubrik获4000万美元B轮融资
    为QNetworkAccessManager添加超时提醒(自己记录一段时间里的下载字节数,用定时器去定期检测,从而判断是否超时)
    DIOCP3 DEMO的编译(去掉VCL前缀)
    Golang环境搭建,Notepad++配置Golang开发环境,Golang发送邮件
    川普当选对中国的好处在哪?(会注重实利,而不是虚的意识形态)
    带你走近AngularJS
    ASP.NET MVC学习之控制器篇扩展性
    微信语音识别及网页获取用户信息
    敏捷和自动化测试
  • 原文地址:https://www.cnblogs.com/2462478392Lee/p/11573640.html
Copyright © 2020-2023  润新知