zoukankan      html  css  js  c++  java
  • 2020牛客多校第八场I-Interseting Computer Game

    https://ac.nowcoder.com/acm/contest/5673/I

    题意

    给了两个数组:({a_1, a_2, dots a_n}, {b_1, b_2, dots b_n})
    第i步可以从(a_i)(b_i)中选择一个数。
    求最后选出的数中,不同的数要最多

    题解

    正解是把每个点对((a_i,b_i))当成一个图中的一条边,如果一个联通分量中有环,则所有点都可以取到,若为树形结构,那么只能取到k-1个点,用并查集判断有没有环即可

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef double db;
    struct READ {
        inline char read() {
        #ifdef Artoriax
            return getchar();
        #endif
            const int LEN = 1 << 18 | 1;
            static char buf[LEN], *s, *t;
            return (s == t) && (t = (s = buf) + fread(buf, 1, LEN, stdin)), s == t ? -1 : *s++;
        }
        inline READ & operator >> (char *s) {
            char ch;
            while (isspace(ch = read()) && ~ch);
            while (!isspace(ch) && ~ch) *s++ = ch, ch = read(); *s = '';
            return *this;
        }
        inline READ & operator >> (string &s) {
            s = ""; char ch;
            while (isspace(ch = read()) && ~ch);
            while (!isspace(ch) && ~ch) s += ch, ch = read();
            return *this;
        }
        template <typename _Tp> inline READ & operator >> (_Tp&x) {
            char ch, flag;
            for(ch = read(),flag = 0; !isdigit(ch) && ~ch; ch = read()) flag |= ch == '-';
            for(x = 0; isdigit(ch); ch = read()) x = x * 10 + (ch ^ '0');
            flag && (x = -x);
            return *this;
        }
    } in;
    
    const int N = 2e5 + 50;
    int f[N];
    int a[N], b[N], lis[N], vis[N];
    int find(int x) {
        return f[x] == x ? x : f[x] = find(f[x]);
    }
    int main() {
        int _; in >> _;
        for (int t = 1; t <= _; t++) {
            int n; in >> n;
            for (int i = 1; i <= n; i++) {
                in >> a[i] >> b[i];
                lis[i*2-1] = a[i], lis[i*2] = b[i];
            }
            sort(lis + 1, lis + 2 * n + 1);
            int m = unique(lis + 1, lis + 2 * n + 1) - lis - 1;
            for (int i = 1; i <= m; i++) f[i] = i, vis[i] = 0;
            for (int i = 1; i <= n; i++) {
                a[i] = lower_bound(lis + 1, lis + m + 1, a[i]) - lis;
                b[i] = lower_bound(lis + 1, lis + m + 1, b[i]) - lis;
                int x = find(a[i]), y = find(b[i]);
                if (x == y) vis[x] = vis[y] = 1;
                else {
                    f[y] = x;
                    if (vis[y]) vis[x] = 1;
                }
            }
            int ans = m;
            for (int i = 1; i <= m; i++) {
                f[i] = find(f[i]);
                if (f[i] == i && !vis[i]) ans--;
            }
            printf("Case #%d: %d
    ", t, ans);
        }
        return 0;
    }
    

    比赛的时候是直接用二分图匹配求解的,用isap卡过去了,二分图的建立方式即i向a[i],b[i]分别连边

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct READ {
        inline char read() {
        #ifdef _WIN32
            return getchar();
        #endif
            static const int IN_LEN = 1 << 18 | 1;
            static char buf[IN_LEN], *s, *t;
            return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
        }
        template <typename _Tp> inline READ & operator >> (_Tp&x) {
            static char c11, boo;
            for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
                if(c11 == -1) return *this;
                boo |= c11 == '-';
            }
            for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
            boo && (x = -x);
            return *this;
        }
    } in;
     
    const int inf = 0x3f3f3f3f;
    const int N = 3e5 + 50;
    struct node {
        int v, cap, flow, nxt;
        node () {}
        node (int v, int cap, int flow, int nxt): v(v), cap(cap), flow(flow), nxt(nxt) {}
    } edge[N * 10];
    int head[N], tot;
    void init() {
        memset(head, -1, sizeof(head));
        tot = 0;
    }
    int dep[N];
    void adde(int u, int v, int w) {
        edge[tot] = node(v, w, 0, head[u]);
        head[u] = tot++;
        edge[tot] = node(u, 0, 0, head[v]);
        head[v] = tot++;
    }
    int gap[N], cur[N];
    void bfs(int s, int t) {
        memset(dep, -1, sizeof(dep));
        memset(gap, 0, sizeof(gap));
        gap[0] = 1;
        queue<int> q;
        dep[t] = 0;
        q.push(t);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int i = head[u]; ~i; i = edge[i].nxt) {
                int v = edge[i].v;
                if (dep[v] != -1) continue;
                q.push(v);
                dep[v] = dep[u] + 1;
                gap[dep[v]]++;
            }
        }
    }
    int S[N];
    int sap(int s, int t, int n) {
        bfs(s, t);
        memcpy(cur, head, sizeof(head));
        int top = 0;
        int u = s;
        int ans = 0;
        while (dep[s] < n) {
            if (u == t) {
                int minn = inf;
                int inser;
                for (int i = 0; i < top; i++) {
                    if (minn > edge[S[i]].cap - edge[S[i]].flow) {
                        minn = edge[S[i]].cap - edge[S[i]].flow;
                        inser = i;
                    }
                }
                for (int i = 0; i < top; i++) {
                    edge[S[i]].flow += minn;
                    edge[S[i] ^ 1].flow -= minn;
                }
                ans += minn;
                top = inser;
                u = edge[S[top] ^ 1].v;
                continue;
            }
            bool flag = false;
            int v;
            for (int i = cur[u]; ~i; i = edge[i].nxt) {
                v = edge[i].v;
                if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]) {
                    flag = true;
                    cur[u] = i;
                    break;
                }
            }
            if (flag) {
                S[top++] = cur[u];
                u = v;
                continue;
            }
            int minn = n;
            for (int i = head[u]; ~i; i = edge[i].nxt) {
                if (edge[i].cap - edge[i].flow && dep[edge[i].v] < minn) {
                    minn = dep[edge[i].v];
                    cur[u] = i;
                }
            }
            gap[dep[u]]--;
            if (!gap[dep[u]]) return ans;
            dep[u] = minn + 1;
            gap[dep[u]]++;
            if (u != s) u = edge[S[--top] ^ 1].v;
        }
        return ans;
    }
    int main() {
        int t; in >> t;
        int cse = 0;
        while (t--) {
            init();
            int n; in >> n;
            map<int, int> mp;
            int cnt = 0;
            for (int i = 1; i <= n; i++) {
                int u, v;
                in >> u >> v;
                if (!mp.count(u)) mp[u] = ++cnt;
                if (!mp.count(v)) mp[v] = ++cnt;
                u = mp[u];
                v = mp[v];
                adde(i, u + n, 1);
                adde(i, v + n, 1);
            }
            for (int i = 1; i <= n; i++) {
                adde(0, i, 1);
            }
            for (int i = 1; i <= cnt; i++) {
                adde(i + n, n + cnt + 1, 1);
            }
            printf("Case #%d: %d
    ", ++cse, sap(0, n + cnt + 1, n + cnt + 1));
        }
        return 0;
    }
    
  • 相关阅读:
    【POJ 1958】 Strange Towers of Hanoi
    【HNOI 2003】 激光炸弹
    【POJ 3263】 Tallest Cow
    【POJ 2689】 Prime Distance
    【POJ 2777】 Count Color
    【POJ 1995】 Raising Modulo Numbers
    【POJ 1845】 Sumdiv
    6月16日省中集训题解
    【TJOI 2018】数学计算
    【POJ 1275】 Cashier Employment
  • 原文地址:https://www.cnblogs.com/artoriax/p/13632336.html
Copyright © 2011-2022 走看看