1 条题解

  • 0
    @ 2025-8-24 21:34:34

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Siyuan
    Dream OIer.

    搬运于2025-08-24 21:34:34,当前版本为作者最后更新于2018-12-27 23:26:00,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    $$\Large\texttt{My Blog}$$


    Description

    题目链接:Luogu 2153

    Elaxia 最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑。现在给出一张学校附近的地图,这张地图中包含 nn 个十字路口和 mm 条街道,Elaxia 只能从一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia 每天从寝室出发跑到学校,保证寝室编号为 11,学校编号为 nn。Elaxia 的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路口。Elaxia 耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天数尽量长。

    数据范围:1n2001\le n\le 2001m2×1041\le m\le 2\times 10^4


    Solution

    首先我们发现需要求路程最短,天数尽量长。那么我们可以考虑最小费用最大流,其中路程为费用,天数为流量。

    由于每个点只能被访问 11 次,那么我们进行拆点,将 ii 拆成 i1i_1i2i_2,其中 i1i_1i2i_2 之间连边 (i1,i2,1,0)(i_1,i_2,1,0)(容量为 11,费用为 00),对于有向图的每条边 (u,v,w)(u,v,w) 连边 (u2,v1,1,w)(u_2,v_1,1,w) 和其反向边 (v1,u2,0,w)(v_1,u_2,0,-w)

    又因为 11nn 可以多次经过,那么源点和汇点分别为 s2s_2t1t_1,然后直接跑网络流即可。

    时间复杂度O(nmf)O(nmf)


    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    const int N=4e2+5,M=1e5+5;
    const int INF=0x3f3f3f3f;
    int n,m,tot=1,lnk[N],cnr[N],ter[M],nxt[M],cap[M],cost[M],dis[N],ret;
    bool vis[N];
    
    void add(int u,int v,int w,int c) {
        ter[++tot]=v,nxt[tot]=lnk[u],lnk[u]=tot,cap[tot]=w,cost[tot]=c;
    }
    void addedge(int u,int v,int w,int c) {
        add(u,v,w,c),add(v,u,0,-c);
    }
    int spfa(int s,int t) {
        memset(dis,0x3f,sizeof(dis));
        memcpy(cnr,lnk,sizeof(lnk));
        std::queue<int> q;
        q.push(s),dis[s]=0,vis[s]=1;
        while(!q.empty()) {
            int u=q.front(); q.pop(),vis[u]=0;
            for(int i=lnk[u];i;i=nxt[i]) {
                int v=ter[i];
                if(cap[i]&&dis[v]>dis[u]+cost[i]) {
                    dis[v]=dis[u]+cost[i];
                    if(!vis[v]) q.push(v),vis[v]=1;
                }
            }
        }
        return dis[t]!=INF;
    }
    int dfs(int u,int t,int flow) {
        if(u==t) return flow;
        vis[u]=1;
        int ans=0;
        for(int i=cnr[u];i;i=nxt[i]) {
            cnr[u]=i;
            int v=ter[i];
            if(!vis[v]&&cap[i]&&dis[v]==dis[u]+cost[i]) {
                int x=dfs(v,t,std::min(cap[i],flow-ans));
                if(x) ret+=x*cost[i],cap[i]-=x,cap[i^1]+=x,ans+=x;
            }
        }
        vis[u]=0;
        return ans;
    }
    int mcmf(int s,int t) {
        int ans=0;
        while(spfa(s,t)) {
            int x;
            while((x=dfs(s,t,INF))) ans+=x;
        }
        return ans;
    }
    int main() {
        scanf("%d%d",&n,&m);
        while(m--) {
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            addedge(u+n,v,1,c);
        }
        for(int i=1;i<=n;++i) addedge(i,i+n,1,0);
        int s=1+n,t=n;
        int ans=mcmf(s,t);
        printf("%d %d\n",ans,ret);
        return 0;
    }
    
    • 1

    信息

    ID
    1156
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者