• 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;
    }
    
    
  • 相关阅读:
    Java反射研究(3)
    Java反射研究(2)
    Java反射研究(1)
    从百度文库中复制文本的方法
    jdk/bin中的native2ascii.exe使用
    EA经典入门教程
    JSP自定义标签(3)
    JSP自定义标签(1)
    将Java doc转换为chm的方法
    多态性——vptr和vtable
  • 原文地址:https://www.cnblogs.com/harutomimori/p/13436150.html
Copyright © 2020-2023  润新知