2020牛客暑期多校训练营(第八场)I-Interesting Computer Game

链接

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

题意

给n对数,从上到下开始取数
每一对有三种操作
1)两个都不选
2)如果a没选过,可以选a
3)如果b没选过,可以选b
问最多可以选多少个数

思路

先说解法:
对每行的两个数字连边,建图
统计图中有多少棵树,点的总数cnt减去树的棵树tot即为答案
再说证明:
对于此题有一个技巧,对于一对数,我们可以用一条无向边将他们连起来,比如a-b,如果我们要选择a,就给这条边加上方向a<-b
现在考虑一组数据:
1 2
1 3
2 4
2 5
很明显根据最优解建出的图应该是:

可以发现对于树的根,它是不在解里的
对于其他样例也是同样的道理
回到技巧的说明中,我们选择一个点而放弃另一个点,等于给一个点的入度变为0,如果在之后的选择中我们选择了这个点,这个点的入度就增加了,也就是说对于这个图,所有入度为0的点就是被抛弃的点
考虑不是树的情况,也就是图存在环,根据上面所说,没有点被抛弃
所以我们的做法是建图->找出所有的树->统计
具体的操作有很多种,比如我们可以对图中的连通块进行遍历,如果连通块中无环,那么连通块对答案的贡献为大小减1,否则贡献就是连通块的大小
而判环和统计连通块的大小就很简单了,dfs并查集,这里贴上我校dalao的bfs做法(其实我没看懂(能跑就行

代码

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ms(a) memset(a, 0, sizeof(a))
#define repu(i, a, b) for (int i = a; i < b; i++)
#define repd(i, a, b) for (int i = a; i > b; i--)
using namespace std;
typedef long long ll;
typedef long double ld;

const int M = int(1e5)*3 + 5;
const int mod = int(1e9) + 7;

struct edge {
    int to;
    int w;
    int next;
};
edge edges[M * 60];
int head[M * 5];
int cnt;
void add(int u, int v, int w) {
    edges[cnt].to = v;
    edges[cnt].w = w;
    edges[cnt].next = head[u];
    head[u] = cnt++;
    edges[cnt].to = u;
    edges[cnt].w = w;
    edges[cnt].next = head[v];
    head[v] = cnt++;
}
void init() {
    cnt = 0;
    memset(head, -1, sizeof(head));
}

map<int, int> m;
int ans = 0;
bool vis[M];
int top[M];
int bfs(int s) {
    if (vis[s]) return 0;
    queue<int> q;
    top[s]=0;
    q.push(s);
    bool cir = 0;
    bool dcir = 0;
    int cnt = 0;

    while (!q.empty()) {
        int u = q.front();
        q.pop();

        if (vis[u]) continue;
        vis[u] = 1;
        dcir=0;

        for (int i = head[u]; ~i; i = edges[i].next) {
            int v = edges[i].to;
            if (vis[v] == 1) {
                if (top[u] == v && dcir == 0) {
                    dcir = 1;
                } else {
                    cir = 1;
                }
                continue;
            }

            q.push(v);
            top[v] = u;
        }
        cnt++;
    }

    return cnt - 1 + cir;
}
void solve() {
    init();
    m.clear();
    ans = 0;
    ms(vis);
    ms(top);

    int n;
    cin >> n;

    int tot = 0;
    repu(i, 0, n) {
        int x, y;
        cin >> x >> y;
        if (m.find(x) == m.end()) {
            m[x] = ++tot;
        }
        if (m.find(y) == m.end()) {
            m[y] = ++tot;
        }
        // cout<<m[x]<<" "<<m[y]<<endl;
        add(m[x], m[y], 1);
    }

    repu(i, 1, tot+1) { ans += bfs(i); }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin >> T;
    repu(t, 1, T + 1) {
        solve();
        cout << "Case #" << t << ": " << ans << endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/harutomimori/p/13436150.html