2019杭电多校1005 Path 最短路+最大流(最小割)

现在假设受众已有 求图的所有最短路径 的前置知识

推荐阅读:白书P209 看懂最大流&最小割

今天没时间重构代码了。。。

就随便注释一下

题目呢是签到题

意思是给一个有向图

一个人要从1点走到n点

我们要阻碍他走最短路

而你堵塞一条边的代价就是这条边的长度

问最小代价

要是看懂了最小割
就知道这题几乎就是板子题

先用优先队列优化最短路,求所有最短路径的所有边
题解的方法可以学一手

采用的方法是先更新好所有点的最短距离 (题中的sp数组)
然后遍历所有边
接着如果说两个点的最短距离之差刚好是边的长度
那么这条边就是在最短路上

就是题解那个蜜汁公式的意思

for(int pos=1;pos<=n;++pos)
    for(auto &e : D::G[pos])
        if(sp[e.to]-sp[pos]==e.v)
            I::AddEdge(pos,e.to,e.v);

上图的下面的for等价于

for(int i=0;i<D::G[pos].size();i++){
    D::Edge e=D::G[pos][i];
}

学一手auto自适应类型

然后用最大流求答案。。。。

似乎就没了

#include 

template 
bool Reduce(T &a,T const &b) {
    return a>b?a=b,1:0;
}

const int XN=1e4+11;
const int INF=2e9;
const long long oo=1e18;

int n;
long long sp[XN];

namespace D {
    struct Edge {
        int to,v;
    };

    std::vector G[XN];
    //优先队列优化
    void Run() {
        static bool ud[XN];
        std::priority_queue,std::vector >,std::greater > > Q;//小根堆
        std::fill(sp+1,sp+1+n,oo);
        std::fill(ud+1,ud+1+n,0);
        sp[1]=0;
        Q.push(std::make_pair(0,1));
        while(!Q.empty()) {
            int pos=Q.top().second;Q.pop();
            if(ud[pos])
                continue;
            ud[pos]=1;
            for(auto int & e : G[pos]) {
                int u=e.to;
                if(Reduce(sp[u],sp[pos]+e.v))
                    Q.push(std::make_pair(sp[u],u));
            }
        }
    }
}

namespace I {
    //最大流求解
    struct Edge {
        int to,cap,v;
        Edge *rev,*pre;
    }*G[XN],*preArc[XN];

    void AddEdge(int x,int y,int c) {
        G[x]=new Edge{y,c,0,NULL,G[x]};
        G[y]=new Edge{x,0,0,G[x],G[y]};
        G[x]->rev=G[y];
    }

    int Aug() {
        int d=INF;
        for(int pos=n;preArc[pos];pos=preArc[pos]->rev->to)
            Reduce(d,preArc[pos]->cap-preArc[pos]->v);
        for(int pos=n;preArc[pos];pos=preArc[pos]->rev->to) {
            preArc[pos]->v+=d;
            preArc[pos]->rev->v-=d;
        }
        return d;
    }

    long long Run() {
        static int num[XN],d[XN];
        static Edge *cArc[XN];
        std::fill(num+1,num+n,0);
        std::fill(d+1,d+1+n,0);
        std::copy(G+1,G+1+n,cArc+1);
        num[0]=n;preArc[1]=0;
        long long flow=0;
        for(int pos=1;d[1]<n;) {
            if(pos==n) {
                flow+=Aug();
                pos=1;
            }
            bool adv=0;
            for(Edge *&e=cArc[pos];e;e=e->pre) {
                int u=e->to;
                if(e->cap>e->v && d[u]+1==d[pos]) {
                    adv=1;
                    preArc[pos=u]=e;
                    break;
                }
            }
            if(!adv) {
                if(--num[d[pos]]==0)
                    break;
                d[pos]=n;
                for(Edge *e=cArc[pos]=G[pos];e;e=e->pre)
                    if(e->cap>e->v)
                        Reduce(d[pos],d[e->to]+1);
                num[d[pos]]++;
                if(pos!=1)
                    pos=preArc[pos]->rev->to;//cArc
            }
        }
        return flow;
    }
}

int main() {
    //freopen("test1.in","r",stdin);
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    int T;std::cin>>T;
    while(T--) {
        int m;std::cin>>n>>m;
        for(int i=1;i<=n;++i) {
            D::G[i].clear();
            I::G[i]=0;
        }
        for(int i=1;i<=m;++i) {
            int x,y,v;
            std::cin>>x>>y>>v;
            D::G[x].push_back({y,v});
        }

        D::Run();

        if(sp[n]==oo)
            std::cout<<0<<'\n';
        else {
            //蜜汁公式 求出所有最短路径边
            for(int pos=1;pos<=n;++pos)
                for(auto &e : D::G[pos])
                    if(sp[e.to]-sp[pos]==e.v)
                        I::AddEdge(pos,e.to,e.v);

            std::cout<<I::Run()<<'\n';
        }
    }
    return 0;
}
全部评论

相关推荐

#简历#先说一说我自己的想法,很多人都很排斥苍穹外卖,认为没什么技术点和含金量,但实际上我觉得恰恰相反,苍穹外卖虽然代码本身并不是你自身能力的证明,但是是作为一个新人学习时很好的跳板和原始框架,在这个框架上进行的改进可以很好的辐射到你自己的个人成果上,并作为你和面试官聊天的筹码大多数人的苍穹外卖只写增删改查,千篇一律,吸引不了面试官,所以这才让大家误以为只要是苍穹外卖就不要写进简历里这种误区,但实际上如果你在原有的层面上进行改进,并作为你的项目亮点和面试官介绍,告诉他你的苍穹外卖和别人的有什么不同,增加了哪些技术难点,这才显得你是完全自己理解了这个项目,并且有自己动手实践项目的能力,而不是就看了个课程就以为自己会了,就当成自己的了,如此一来,这反而成为你的加分项苍穹外卖为什么看的人最多,说明它好啊,如果它不好,为什么看的人还这么多,想清楚这个逻辑,我觉得要做的最重要的事,就是如何在原有框架上进行改进提效,比起听其他人的话重新搞一个项目性价比高得多,而且我亲测项目并没有成为我找到工作的阻碍,我投的大厂一大半都给我面试了,而且很多不止一个部门,退一万步说,当你手头没有其他项目的时候,有苍穹外卖总比什么都没有的好很多,不需要因为苍穹外卖有任何心理负担关于简历的任何部分都欢迎大家提意见,十分感谢大家,祝大家找实习+秋招顺利上岸,offer拿到手软#简历中的项目经历要怎么写##我的上岸简历长这样##最后再改一次简历##简历##简历被挂麻了,求建议#
点赞 评论 收藏
转发
猿辅导 Java后端日常实习 800一天
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务