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;
    }
  • 相关阅读:
    Nodejs-内置核心模块&npm包管理工具

    python 内置函数
    序列化和反序列化(json 和pickle)dumps 为序列化, json为反序列化
    迭代器iter()
    生成器 yield
    装饰器的解释说明
    面向过程中的局部变量(global)
    函数的参数设定
    集合的基本操作
  • 原文地址:https://www.cnblogs.com/xiongtao/p/11248452.html
Copyright © 2011-2022 走看看