zoukankan      html  css  js  c++  java
  • SGU 185 Two shortest

    SGU_185

        这个题目被内存卡的严重头晕……

        其实思路还是满直观的,由于要两条路不相交,只要用网络流就行,再加上要两条最短路,那么就最小费用最大流,最后看两条路的费用和是不是最短路的两倍即可。但如果裸着这样写,由于无向边相当于两条有向边,不好意思,内存爆了……开小点吧,不好意思,RE了……

        晕……那还是换网络流写吧,这样少个记录费用的数组,可以先用dij从1开始搞遍最短路,再从N开始搞遍最短路,再遍历一遍所有边就知道哪条边是最短路上的边了,而且还知道了这条边的方向,那么根据这些最短路上的边组成的图做最大流就可以了,最后看总流量是不是为2。

        当然敲到这里就发现了省内存的方法,只要先找到哪些边是最短路上的边,那么这些边就会定向了,于是内存就可以剩一半了,这时候再用费用流就不会爆内存了,不过你写着写着就会发现,好像这个费用流要边权没啥用哦,因为费用是没关系的,反正都是最短路上的边。那就把费用设成0吧,算了,干脆不要费用这个数组了,于是最后写着写着,咦,又写回网络流了,不要费用的最小费用最大流算法不就是EK嘛=_=

        不过值得一提的是,在输出最终路径时不能这样:先做一遍最大流,把增广路存下来,再做一遍最大流,再把增广路存下来,然后输出两条增广路。因为第二次的增广路有可能走逆向边的,也就是说相当于反悔之前的某个走法,这样显然就不对了,因为相当于这条边没有走但两次增广路中又都包含了这条边。不过可以最后根据残量网络直接沿残量为0的正向边走到终点,顺便把残量置1,这样走两遍就输出了那两条路径了。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXD 410
    #define MAXM 160010
    #define INF 0x3f3f3f3f
    int N, M, g[MAXD][MAXD], first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM];
    int S, T, q[MAXD], d[MAXD], work[MAXD], diss[MAXD], dist[MAXD], pre[MAXD];
    void init()
    {
        int i, x, y, z;
        memset(g, 0x3f, sizeof(g));
        for(i = 0; i < M; i ++)
        {
            scanf("%d%d%d", &x, &y, &z);
            g[x][y] = g[y][x] = z;    
        }
    }
    void dij(int S, int T, int *dis)
    {
        int i, j, k, min;
        memset(dis, 0x3f, sizeof(diss[0]) * (N + 1));
        memset(d, 0, sizeof(d[0]) * (N + 1));
        dis[S] = 0;
        for(;;)
        {
            min = INF;
            for(i = 1; i <= N; i ++) if(!d[i] && dis[i] < min) min = dis[k = i];
            if(min == INF) break;
            d[k] = 1;
            for(i = 1; i <= N; i ++) dis[i] = std::min(dis[i], dis[k] + g[k][i]);
        }
    }
    int bfs()
    {
        int i, j, rear = 0;
        memset(d, -1, sizeof(d[0]) * (N + 1));
        d[S] = 0, q[rear ++] = S;
        for(i = 0; i < rear; i ++)
            for(j = first[q[i]]; j != -1; j = next[j])
                if(flow[j] && d[v[j]] == -1)
                {
                    d[v[j]] = d[q[i]] + 1, q[rear ++] = v[j];
                    if(v[j] == T) return 1;    
                }
        return 0;
    }
    int dfs(int cur, int a)
    {
        if(cur == T) return a;
        for(int &i = work[cur]; i != -1; i = next[i])
            if(flow[i] && d[v[i]] == d[cur] + 1)
                if(int t = dfs(v[i], std::min(a, flow[i])))
                {
                    flow[i] -= t, flow[i ^ 1] += t;
                    return t;    
                }    
        return 0;
    }
    int dinic()
    {
        int ans = 0, t;
        while(bfs())
        {
            memcpy(work, first, sizeof(first[0]) * (N + 1));
            while(t = dfs(S, INF))
                ans += t;
        }
        return ans;
    }
    void add(int x, int y, int z)
    {
        v[e] = y, flow[e] = z;
        next[e] = first[x], first[x] = e ++;    
    }
    void print()
    {
        int i, cur = 1;
        for(;;)
        {
            if(cur == T)
            {
                printf("%d\n", cur);
                return ;    
            }
            printf("%d ", cur);
            for(i = first[cur]; i != -1; i = next[i])
                if((i & 1) == 0 && flow[i] == 0)
                {
                    flow[i] = 1, cur = v[i];
                    break;    
                }
        }    
    }
    void solve()
    {
        int i, j;
        dij(1, N, diss), dij(N, 1, dist);
        if(diss[N] == INF)
        {
            printf("No solution\n");
            return ;    
        }
        memset(first, -1, sizeof(first[0]) * (N + 1)), e = 0;
        for(i = 1; i <= N; i ++)
            for(j = 1; j <= N; j ++)
                if(i != j && diss[i] + g[i][j] + dist[j] == diss[N])
                    add(i, j, 1), add(j, i, 0);
        S = 0, T = N;
        add(S, 1, 2), add(1, S, 0);
        if(dinic() != 2)
            printf("No solution\n");
        else
            print(), print();
    }
    int main()
    {
        while(scanf("%d%d", &N, &M) == 2)
        {
            init();
            solve();    
        }
        return 0;    
    }
  • 相关阅读:
    VisualSVN-Server windows 版安装时报错 "Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details."
    Pytest 单元测试框架之初始化和清除环境
    Pytest 单元测试框架入门
    Python(email 邮件收发)
    Python(minidom 模块)
    Python(csv 模块)
    禅道简介
    2020年最好的WooCommerce主题
    Shopify网上开店教程(2020版)
    WooCommerce VS Magento 2020:哪个跨境电商自建站软件更好?
  • 原文地址:https://www.cnblogs.com/staginner/p/2647342.html
Copyright © 2011-2022 走看看