zoukankan      html  css  js  c++  java
  • bzoj1266: [AHOI2006]上学路线route

    最短路+最小割

    首先如何使最短路变长?就是要每一条最短路都割一条边。
    我们求出每个点到点1和点n的距离,就可以知道哪些边在最短路上(一开始没有想到求到0和n的距离,想用floyd,但是n=500,怕超时。)

    第二步呢,我们把每条在最短路上的边加入一个新图,跑最小割就可以了(把所有最短路都割掉一条边,最短路就变长了,这个也没想到)

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 500 + 10;
    const int maxm = 300000 + 10;
    const int inf = 0x3f3f3f3f;
    
    struct Edge {
        int u,v,t,c;
    }e[maxm];
    
    int g[maxn],v[maxm],next[maxm],c[maxm],eid;
    int n,m,S,T,u,vid;
    int gap[maxn],dist[2][maxn],d[maxn];
    int q[maxm*10],l,r;
    bool inque[maxn];
    
    void addedge(int a,int b,int C) {
        v[eid]=b; c[eid]=C; next[eid]=g[a]; g[a]=eid++;
    }
    
    void build() {
        memset(g,-1,sizeof(g));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) {
            scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].t,&e[i].c);    
            addedge(e[i].u,e[i].v,e[i].t);
            addedge(e[i].v,e[i].u,e[i].t);
        }
    }
    
    void spfa(int S,int dist[]) {
        l=r=0;
        q[r++]=S;
        memset(dist,0x3f,sizeof(dist));
        dist[S]=0;
        while(l<r) {
            inque[u=q[l++]]=0;
            for(int i=g[u];~i;i=next[i]) if(dist[v[i]]>dist[u]+c[i]) {
                dist[v[i]]=dist[u]+c[i];
                if(!inque[v[i]]) inque[q[r++]=v[i]]=1;    
            }
        }
    }
    
    void predo() {    
        memset(dist,0x3f,sizeof(dist));
        spfa(1,dist[0]); spfa(n,dist[1]);
        printf("%d
    ",dist[0][n]);
        S=1; T=n;
        memset(g,-1,sizeof(g)); eid=0;
        
        for(int i=1;i<=m;i++) {
            if(dist[0][e[i].u]+e[i].t+dist[1][e[i].v]==dist[0][n]) {
                addedge(e[i].u,e[i].v,e[i].c);
                addedge(e[i].v,e[i].u,0);
            }
            if(dist[0][e[i].v]+e[i].t+dist[1][e[i].u]==dist[0][n]) {
                addedge(e[i].v,e[i].u,e[i].c);
                addedge(e[i].u,e[i].v,0);
            }
        }
    }
    
    int ISAP(int u,int flow) {
        if(u==T) return flow;
        int cur=0,aug,mindist=vid;
        for(int i=g[u];~i;i=next[i]) if(c[i] && d[v[i]]+1==d[u]) {
            aug=ISAP(v[i],min(flow-cur,c[i]));
            c[i]-=aug;
            c[i^1]+=aug;
            cur+=aug;
            if(cur==flow || d[S]>=vid) return cur;
        }
        if(cur==0) {
            if(!--gap[d[u]]) {
                d[S]=vid;
                return cur;
            }
            for(int i=g[u];~i;i=next[i]) if(c[i]) 
                mindist=min(mindist,d[v[i]]);
            ++gap[d[u]=mindist+1];
        }
        return cur;
    }
    
    void solve() {
        int res=0;
        memset(d,0,sizeof(d));
        vid=n;
        gap[0]=vid;
        while(d[S]<vid) res+=ISAP(S,inf);
        printf("%d
    ",res);
    }
    
    int main() {
        build();
        predo();
        solve();
        return 0;    
    }
  • 相关阅读:
    斐波那契数列
    旋转数组的最小数字
    用两个栈实现队列
    重建二叉树
    从尾到头打印链表
    2020/01/11,人活着是为了一口气
    2020/01/11,放肆和克制,敏感层次
    2020/01/11,记忆单元
    2020/01/11,经济基础决定高层建筑和个性
    git
  • 原文地址:https://www.cnblogs.com/invoid/p/5621417.html
Copyright © 2011-2022 走看看