zoukankan      html  css  js  c++  java
  • 洛谷P5022 旅行(NOIP提高组2018 D2T1)题解 贪心/去环

    题目链接:https://www.luogu.com.cn/problem/P5022

    解题思路:

    这里最重要的是数据范围里面的 (m=n-1) 或者 (m=n)

    (m=n-1) 的时候是一棵树,我们按照从当前节点找编号最小的子节点的策略进行深搜就能够解决这个问题。

    (m=n) 的时候只存在一个环,我们只需要找到环上面的每一条边,然后枚举每一条边,在假设这条边被去掉的情况下(去掉一条环上面的边这个图就又变成了树)进行给予上述贪心思想的搜索。

    所以总的时间复杂度是 (O(n^2)) (因为这里 (n)(m) 最多相差 (1),所以这么说)。

    实现起来要注意一些袭击,比如邻接表最好一遍排序,接下来就用就可以了。

    实现代码如下(略显繁琐):

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 5050;
    struct Edge {
        int u, v, nxt;
        Edge() {};
        Edge(int _u, int _v, int _nxt) { u = _u; v = _v; nxt = _nxt; }
    } edge[maxn<<1];
    int n, m, ecnt, head[maxn];
    void init() {
        ecnt = 0;
        memset(head, -1, sizeof(int)*(n+1));
    }
    void addedge(int u, int v) {
        edge[ecnt] = Edge(u, v, head[u]); head[u] = ecnt ++;
        edge[ecnt] = Edge(v, u, head[v]); head[v] = ecnt ++;
    }
    bool flag[maxn<<1], vise[maxn<<1];
    int fe[maxn<<1], dep[maxn];
    void dfs1(int u, int d) {   // 用来构造一棵树,从而找到没有使用的那条边
        dep[u] = d;
        for (int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].v;
            if (!dep[v]) {
                dep[v] = dep[u] + 1;
                vise[i] = vise[i^1] = true;
                fe[v] = i^1;
                dfs1(v, d+1);
            }
        }
    }
    void after_dfs1() { // 标记所有在环上的边
        int u, v;
        for (int i = 0; i < ecnt; i += 2) {
            if (!vise[i]) {
                flag[i] = flag[i^1] = true;
                u = edge[i].u;
                v = edge[i].v;
                break;
            }
        }
        while (u != v) {
            if (dep[u] < dep[v]) swap(u, v);
            int i = fe[u];
            flag[i] = flag[i^1] = true;
            u = edge[i].v;
        }
    }
    vector<int> g[maxn];
    int gsz[maxn];
    int ans[maxn], tmp[maxn], tmpcnt;
    void before_dfs2() {
        for (int u = 1; u <= n; u ++) {
            for (int i = head[u]; i != -1; i = edge[i].nxt) {
                int v = edge[i].v;
                g[u].push_back(v);
            }
            sort(g[u].begin(), g[u].end());
            gsz[u] = g[u].size();
        }
    }
    void dfs2(int u, int p, int ii) {
        // printf("dfs2 : u = %d , p = %d , ii = %d
    ", u, p, ii);
        tmp[tmpcnt++] = u;
        int sz = gsz[u];
        // printf("	g[%d].size() == %d
    ", u, sz);
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i];
            if (v != p && !(u == edge[ii].u && v == edge[ii].v) && !(u == edge[ii].v && v == edge[ii].u))
                dfs2(v, u, ii);
        }
    }
    int main() {
        scanf("%d%d", &n, &m);
        init();
        for (int i = 0; i < m; i ++) {
            int u, v;
            scanf("%d%d", &u, &v);
            addedge(u, v);
        }
        before_dfs2();
        if (m == n-1) { // 本身就是一棵树
            dfs2(1, -1, -1);
            for (int i = 0; i < n; i ++) printf("%d ", tmp[i]);
        }
        else {  // 存在一个环
            dfs1(1, 1);
            after_dfs1();
            bool first = true;
            for (int i = 0; i < ecnt; i += 2) {
                if (flag[i]) {
                    tmpcnt = 0;
                    dfs2(1, -1, i);
                    bool flag = false;
                    if (first) {
                        flag = true;
                    }
                    else {
                        for (int i = 0; i < n; i ++) {
                            if (ans[i] != tmp[i]) {
                                if (ans[i] > tmp[i]) flag = true;
                                break;
                            }
                        }
                    }
                    if (flag) {
                        if (first) {
                            first = false;
                        }
                        for (int i = 0; i < n; i ++) ans[i] = tmp[i];
                    }
                }
            }
            for (int i = 0; i < n; i ++) printf("%d ", ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    SD卡测试
    测试人员可能会遇到的问题
    HDU 1024 Max Sum Plus Plus
    HDU 1176 免费馅饼
    HDU 1257 最少拦截系统
    HDU 1087 Super Jumping! Jumping! Jumping!
    poj 1328 Radar Installation
    poj 1753 Flip Game
    HDU 1003 Max Sum
    HDU 5592 ZYB's Premutation(BestCoder Round #65 C)
  • 原文地址:https://www.cnblogs.com/quanjun/p/13149563.html
Copyright © 2011-2022 走看看