题解 | #Puzzle: Wagiri#

Puzzle: Wagiri

https://ac.nowcoder.com/acm/contest/81601/D

输入时将qie存起来,将所有lun使用tarjan进行缩点,最后使用并查集, 将存起来的qie加上,看看是否能将所有点串起来

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10, M = 1e6 + 10;

struct Edge{int u, v;};

int n, m;
int h[N], hs[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
int id[N], dcc_cnt;
vector<int> dcc[N];

vector<Edge> qie;

bool in_ans[M];

int p[N];

vector<Edge> ans;

int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void merge(int x, int y) {
    int px = find(x), py = find(y);
    if (px == py) return;
    p[px] = py;
}

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void tarjan(int u, int from) {
    dfn[u] = low[u] = ++ timestamp;
    stk[ ++ top] = u;
    
    for (int i = h[u]; i != -1; i = ne[i]) {
        int j = e[i];
        if (!dfn[j]) {
            tarjan(j, i);
            low[u] = min(low[u], low[j]);
        } else if (i != (from ^ 1)) {
            low[u] = min(low[u], dfn[j]);
        }
    }
    
    if (dfn[u] == low[u]) {
        dcc_cnt ++;
        int y;
        do {
            y = stk[top --];
            id[y] = dcc_cnt;
            dcc[dcc_cnt].push_back(y);
        } while (y != u);
    }
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) h[i] = -1;
    
    for (int i = 1; i <= m; i ++) {
        int u, v; string w;
        cin >> u >> v >> w;
//         cout << u << " " << v << " " << w << endl;
        if (w == "Lun") {
            add(u, v); add(v, u);
        } else if (w == "Qie") { // 先把切边存起来
            qie.push_back((Edge){u, v});
        }
    }
    for (int i = 1; i <= n; i ++)
        if (!dfn[i])
            tarjan(i, -1);

    for (int i = 1; i <= n; i ++)
        if (!id[i]) {
            dcc_cnt ++;
            id[i] = dcc_cnt;
            dcc[dcc_cnt].push_back(i);
        }
    
    bool flag = true;
    
    for (int i = 1; i <= n; i ++) p[i] = i;
    
    for (int idx = 1; idx <= dcc_cnt; idx ++) {
        for (auto u : dcc[idx]) {
            for (int i = h[u]; i != -1; i = ne[i]) {
                int j = e[i];
                if (in_ans[i] || in_ans[i ^ 1] || id[j] != idx) continue;
                in_ans[i] = in_ans[i ^ 1] = true;
                ans.push_back((Edge) {u, j});
                merge(u, j);
            }
        }
    }
    
    for (auto e : qie) {
        if (find(e.u) == find(e.v)) continue;
        ans.push_back(e);
        merge(e.u, e.v);
    }
    
    for (int i = 1; i <= n; i ++)
        if (find(i) != find(1)) 
        {
            flag = false;
            break;
        }
    
    if (flag) {
        cout << "YES" << endl;
        cout << ans.size() << endl;
        for (auto a : ans) {
            cout << a.u << " " << a.v << endl;
        }
    } else {
        cout << "NO" << endl;
    }
//     for (int i = 1; i <= n; i ++) cout << dfn[i] << " " << low[i] << endl;
//     for (int i = 1; i <= n; i ++) {
//         for (int j = h[i]; j != -1; j = ne[j]) {
//             int k = e[j];
//             cout << k << " ";
//         }
//         cout << endl;
//     }
}

int main() {
    int t; t = 1;
    while (t --)
        solve();
}
全部评论

相关推荐

HR_丸山彩同学:你的项目描述里,系统设计讲了很多:MemCube是什么、三级存储架构怎么设计、四种遗忘策略分别是什么。这些面试的时候讲没问题,但简历上不需要这么细。 简历要突出的是影响力,不是实现细节。面试官看简历的时候想知道的是「这个项目有多大价值」,不是「这个项目具体怎么实现的」。实现细节是面试时候聊的 怎么改:技术细节可以精简为一句「采用三级存储架构+四种遗忘策略」,把省出来的篇幅用来写影响力。比如:项目有没有开源?有没有写成技术博客?有没有被别人使用过? 校园经历没有任何信息量,任何人都可以写这句话,写了等于没写。更关键的是,你投的是技术岗,校园活动经历本来就不是加分项。如果非要写,必须写出具体的数字和成果。如果你没有这些数字,那就老老实实删掉 「端到端耗时缩减30-40%」要给出确切数字和绝对值。从1000ms降到600ms是降了40%,从100ms降到60ms也是降了40%,但这两个含义完全不一样。其他也是,涉及到数据,准备好证据,口径统一,面试会问 「熟练」「熟悉」「了解」混在一起用,读起来很乱。而且「了解前端需求」最好改成「具备前后端协作经验」
点赞 评论 收藏
分享
评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务