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 = '\0';
        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\n", 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\n", ++cse, sap(0, n + cnt + 1, n + cnt + 1));
    }
    return 0;
}
posted @ 2020-09-08 14:26  Artoriax  阅读(183)  评论(0编辑  收藏  举报