zoukankan      html  css  js  c++  java
  • HITOJ 2739 The Chinese Postman Problem(欧拉回路+最小费用流)

    The Chinese Postman Problem

    My Tags   (Edit)
      Source : bin3
      Time limit : 1 sec   Memory limit : 64 M

    Submitted : 503, Accepted : 172

    A Chinese postman is assigned to a small town in China to deliver letters. In this town, each street is oriented and connects exactly two junctions. The postman's task is to start at the post office and pass each street at least once to deliver letters. At last, he must return to the post office.

    Can you help him to make sure whether there exist feasible routes for him and find the minimum distance from all the feasible routes.

     

    Input

     

    Input contains multiple test cases. The first line is an integer T, the number of test cases. Each case begins with two integers N, M, with 2 ≤ N ≤ 100, 1 ≤ M ≤ 2000, representing the number of junctions and the number of streets respectively.

    Then M lines will follow, each denoting a street. A street is represented by three integers u, v, d, with 0 ≤ u, v < N, 0 < d ≤ 1000, meaning this street whose length is d connects the junction u and v and the postman can only travel from junction u to v. Junctions are numbered from 0 to N-1. Junction 0 is always the post office. Note that there may be more than one street connecting the same pair of junctions.

     

     

    Output

     

    Output one line for each test case. If there exist feasible routes for the postman, output the minimum distance. Otherwise, output -1.

     

     

    Sample Input

     

     

    3
    2 1
    0 1 3
    4 4
    0 1 1
    1 2 2
    2 3 3
    3 0 4
    4 7
    0 1 1
    1 2 2
    2 3 3
    3 0 4
    1 3 5
    3 1 2
    1 3 2
    

     

     

    Sample Output

     

     

    -1
    10
    21

    题目链接:HIT 2739

    题意就是用最少的费用把所有边跑一边,并最终回到源点,这个跟欧拉回路有一点关系,有向图欧拉回路的充要条件就是所有点的出度和入度相等,并且基图要连通,这题的边方向已经是不能改的了,因此只能通过重复走来使得到达另一些重边,即多走几遍一些边,把某些点的出度和入度补成一样的,那么可以统计所有点的入度和出度之差记为$deg_i=in_i-out_i$,如果一个点$deg_i>0$,说明这个点的入度比较大,需要补充一些,因此要和源点连边;若$deg_i<0$即入度较大,则和汇点连边,这样一来就就可以构图使得流量从入度多的点流向出度多的点,平衡了入度和出度。

    代码:

    #include <stdio.h>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <bitset>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define LC(x) (x<<1)
    #define RC(x) ((x<<1)+1)
    #define MID(x,y) ((x+y)>>1)
    #define fin(name) freopen(name,"r",stdin)
    #define fout(name) freopen(name,"w",stdout)
    #define CLR(arr,val) memset(arr,val,sizeof(arr))
    #define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
    typedef pair<int, int> pii;
    typedef long long LL;
    const double PI = acos(-1.0);
    const int N = 110;
    const int M = 2010;
    struct edge
    {
        int to, nxt, cap, cost;
        edge() {}
        edge(int _to, int _nxt, int _cap, int _cost): to(_to), nxt(_nxt), cap(_cap), cost(_cost) {}
    } E[(M + N) << 1];
    int head[N], tot;
    int d[N], pre[N], pat[N], mc, mf;
    bitset<N>vis;
    int n, m, deg[N];
     
    void init()
    {
        CLR(head, -1);
        tot = 0;
        mc = mf = 0;
        CLR(deg, 0);
    }
    inline void add(int s, int t, int cap, int cost)
    {
        E[tot] = edge(t, head[s], cap, cost);
        head[s] = tot++;
        E[tot] = edge(s, head[t], 0, -cost);
        head[t] = tot++;
    }
    int spfa(int s, int t)
    {
        queue<int>Q;
        Q.push(s);
        CLR(d, INF);
        vis.reset();
        vis[s] = 1;
        d[s] = 0;
        while (!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            vis[u] = 0;
            for (int i = head[u]; ~i; i = E[i].nxt)
            {
                int v = E[i].to;
                if (d[v] > d[u] + E[i].cost && E[i].cap > 0)
                {
                    d[v] = d[u] + E[i].cost;
                    pre[v] = u;
                    pat[v] = i;
                    if (!vis[v])
                    {
                        vis[v] = 1;
                        Q.push(v);
                    }
                }
            }
        }
        return d[t] != INF;
    }
    void MCMF(int s, int t)
    {
        int i;
        while (spfa(s, t))
        {
            int df = INF;
            for (i = t; i != s; i = pre[i])
                df = min(df, E[pat[i]].cap);
            for (i = t; i != s; i = pre[i])
            {
                E[pat[i]].cap -= df;
                E[pat[i] ^ 1].cap += df;
            }
            mf += df;
            mc += df * d[t];
        }
    }
    namespace DSU
    {
    int pre[N], num;
    void init()
    {
        CLR(pre, -1);
        num = n;
    }
    int Find(int n)
    {
        return pre[n] == -1 ? n : pre[n] = Find(pre[n]);
    }
    void Merge(int a, int b)
    {
        int fa = Find(a), fb = Find(b);
        if (fa == fb)
            return ;
        pre[fb] = fa;
        --num;
    }
    int isconnect()
    {
        return num == 1;
    }
    }
    int main(void)
    {
        int T, a, b, w, i;
        scanf("%d", &T);
        while (T--)
        {
            init();
            scanf("%d%d", &n, &m);
            DSU::init();
            int ori = 0;
            for (i = 0; i < m; ++i)
            {
                scanf("%d%d%d", &a, &b, &w);
                DSU::Merge(a, b);
                add(a, b, INF, w);
                ori += w;
                --deg[a];
                ++deg[b];
            }
            if (!DSU::isconnect())
                puts("-1");
            else
            {
                int S = n, T = n + 1;
                int sf = 0;
                for (i = 0; i < n; ++i)
                {
                    if (deg[i] > 0)
                        add(S, i, deg[i], 0);
                    else if (deg[i] < 0)
                    {
                        add(i, T, -deg[i], 0);
                        sf -= deg[i];
                    }
                }
                MCMF(S, T);
                printf("%d
    ", mf == sf ? mc + ori : -1);
            }
        }
        return 0;
    }
  • 相关阅读:
    常见字符编码扫盲(UTF,Unicode, GB2312) 四
    Ogre 实用技巧 四
    CEGUI中文显示问题的解决方法 四
    大幅革新 AMD下一代图形产品前瞻 四
    力争上游 ——我眼中的“计算机产业链” 四
    养成 SQL SERVER 的好习惯 四
    说说 Windows 中的中文字体 四
    Unicode字符集和多字节字符集关系 四
    各种电影 四
    [projectEuler.net]12
  • 原文地址:https://www.cnblogs.com/Blackops/p/7367404.html
Copyright © 2011-2022 走看看