zoukankan      html  css  js  c++  java
  • HDU 3605 Escape

    HDU_3605

        之所以写这个题目是因为偶然看到了用匈牙利算法做二分图多重匹配这么个东西,看完之后发现只是在原有求二分图最大匹配的基础上对匈牙利算法做了一点拓展,代码还是很好写的,而且效率也很不错。

        如果用网络流做的话,这么多点是承受不了的,但由于M很小,可以将N个点适应各个星球的M个数字综合起来看成一个二进制数,这样就能把N分成2^M类,这样图的顶点的数量就降下来了,于是再用网络流求解就OK了。不过即便这么费事地优化了原图,和裸着用匈牙利算法写的代码相比效率也才快100ms左右,可见匈牙利算法还是很高效的。

        至于那些100ms左右的程序应该是用了读入优化以及各种其他的优化吧,这个题用读入优化效果还是很明显的。

    View Code // 二分图多重匹配算法
    #include<stdio.h>
    #include<string.h>
    #define MAXD 100010
    #define MAXM 1000010
    int N, M, n[15], m[15], yM[15][MAXD], visy[15];
    int first[MAXD], e, next[MAXM], v[MAXM];
    void add(int x, int y)
    {
        v[e] = y;
        next[e] = first[x], first[x] = e ++;
    }
    void init()
    {
        int i, j, k;
        memset(first, -1, sizeof(first[0]) * N), e = 0;
        for(i = 0; i < N; i ++)
            for(j = 0; j < M; j ++)
            {
                scanf("%d", &k);
                if(k) add(i, j);
            }
        for(i = 0; i < M; i ++) scanf("%d", &m[i]);
    }
    int searchpath(int cur)
    {
        int i, j;
        for(i = first[cur]; i != -1; i = next[i])
            if(!visy[v[i]])
            {
                visy[v[i]] = 1;
                if(n[v[i]] < m[v[i]])
                {
                    yM[v[i]][n[v[i]] ++] = cur;
                    return 1;
                }
                for(j = 0; j < n[v[i]]; j ++)
                    if(searchpath(yM[v[i]][j]))
                    {
                        yM[v[i]][j] = cur;
                        return 1;
                    }
            }
        return 0;
    }
    int match()
    {
        int i, j, k;
        memset(n, 0, sizeof(n));
        for(i = 0; i < N; i ++)
        {
            memset(visy, 0, sizeof(visy));
            if(!searchpath(i)) return 0;
        }
        return 1;
    }
    void solve()
    {
        printf("%s\n", match() ? "YES" : "NO");
    }
    int main()
    {
        while(scanf("%d%d", &N, &M) == 2)
        {
            init();
            solve();
        }
        return 0;
    }
    View Code // 网络流算法
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXD 1044
    #define MAXM 22558
    #define INF 0x3f3f3f3f
    int N, M, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM];
    int S, T, d[MAXD], q[MAXD], work[MAXD], num[MAXD];
    void add(int x, int y, int z)
    {
        v[e] = y, flow[e] = z;
        next[e] = first[x], first[x] = e ++;
    }
    void init()
    {
        int i, j, k, x, cnt;
        memset(num, 0, sizeof(num));
        cnt = 0;
        for(i = 1; i <= N; i ++)
        {
            x = 0;
            for(j = 0; j < M; j ++)
                scanf("%d", &k), x = x << 1 | k;
            if(!num[x]) ++ cnt;
            ++ num[x];
        }
        S = 0, T = cnt + M + 1;
        memset(first, -1, sizeof(first[0]) * (T + 1)), e = 0;
        for(i = M; i >= 1; i --)
        {
            scanf("%d", &x);
            add(i, T, x), add(T, i, 0);
        }
        cnt = 0;
        for(i = 0; i < 1024; i ++)
            if(num[i])
            {
                ++ cnt;
                add(S, M + cnt, num[i]), add(M + cnt, S, 0);
                for(j = 0; j < M; j ++)
                    if(1 << j & i)
                        add(M + cnt, j + 1, num[i]), add(j + 1, M + cnt, 0);
            }
    }
    int bfs()
    {
        int i, j, rear = 0;
        memset(d, -1, sizeof(d[0]) * (T + 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]) * (T + 1));
            while(t = dfs(S, INF))
                ans += t;
        }
        return ans;
    }
    void solve()
    {
        printf("%s\n", dinic() == N ? "YES" : "NO");
    }
    int main()
    {
        while(scanf("%d%d", &N, &M) == 2)
        {
            init();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    leetcode 29-> Divide Two Integers without using multiplication, division and mod operator
    ros topic 发布一次可能会接收不到数据
    python中的print()、str()和repr()的区别
    python 部分函数
    uiautomatorviewer错误 unable toconnect to adb
    pyqt 不规则形状窗口显示
    appium 计算器demo
    Spring 3.0 注解注入详解
    Spring Autowire自动装配
    restful 学习地址
  • 原文地址:https://www.cnblogs.com/staginner/p/2644743.html
Copyright © 2011-2022 走看看