zoukankan      html  css  js  c++  java
  • hdu 6582 path(最短路+最小割)

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

    题意:有n个点,m条单向带权边,起点为1,终点为n,如果开始没有最短路输出0,现在想堵住一些路,使堵之后的最短路值变大,或不存在。堵路的花费就是边的权值,问最小花费。

    思路:找到最短路核心边,再重新建边,跑一遍最小割即可。找最短路核心边要正向建边找每点到起点的距离(假设为d[i]),再反向建边找每点到终点的距离(假设为d2[i]),如果一条边起点为u,终点为v,边权为w,若d[u]+d2[v]+w==d[n]则这是一条最短路核心边。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring> 
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long ll;
    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;
    }
  • 相关阅读:
    Caffe学习系列(9):solver优化方法
    Caffe学习系列(8):solver,train_val.prototxt,deploy.prototxt及其配置
    模式识别与图像处理笔试题
    图像增强与图像复原
    hough变换检测线和圆
    C++关键字:mutable(转)
    JS 时间格式化函数
    为当前的div 动态添加一个样式
    曾经感动过我们的文字 今天是否还有印象?——v1
    关于模态框 大小的设置 最大 中等 小小
  • 原文地址:https://www.cnblogs.com/xiongtao/p/11248452.html
Copyright © 2011-2022 走看看