zoukankan      html  css  js  c++  java
  • Cf #434 Div.1 D Wizard's Tour [构造题]

    WizardsTourWizard's Tour


    color{blue}{最初想法}

    考虑枚举每个边 (u,v)(u, v), 设 uu 连出的点中度数最小的点为 aa, vv 连出的点中度数最小的点为 bb,
    比较 u,au, av,bv, b 的度数和大小, 贪心地选取度数较小的点, 得到一个三元路径,
    使用 multisetmultiset 维护度数, 枚举边按以上方法找路径即可 .
    代码纪念


    color{red}{正解部分}

    先从图中剥离出一颗树, 然后 DFSDFS, 从底向顶处理, 设当前节点为 ii, 度数为 cnticnt_i,

    • cnticnt_i 为偶数 2n2n , 则直接转化为 nn 条路径 .
    • cnticnt_i 为奇数 2n12n-1, 则连向父亲的边保存, 其余构成 (2n2)/2(2n-2)/2 条路径 .

    这样构造, 可以使得最后至多留下一条边, 这条边是连向根节点的 .


    color{red}{实现部分}

    DFSDFS 到一个点 kk 时, 其连出去的点包含以下类型 downarrow

    • 儿子
    1. 使用了与父亲相连的边的儿子
    2. 没有使用 …
    • 父亲
    1. 需要使用与父亲相连的边
    2. 不需要 …
    • 非子非父
    1. 已经连过边
    2. 没有…

    • 注意根节点没有父亲 .
    • 可以使用类似网络流的建图方式删边 .
    • 使用标记数组 vis[]vis[] 辅助建树 .
    • 使用标记数组 usefa[]use_fa[] 记录是否使用了 fafa 的边 .
    #include<bits/stdc++.h>
    #define reg register
    #define pb push_back
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 200005;
    
    int N;
    int M;
    int num0;
    int A_cnt;
    int cnt[maxn];
    int vis[maxn];
    int head[maxn];
    int Ans[maxn][3];
    int use_fa[maxn];
    
    std::vector <int> A[maxn];
    
    struct Edge{ int nxt, to; } edge[maxn<<1];
    
    void Add(int from, int to){
            edge[++ num0] = (Edge){ head[from], to };
            head[from] = num0;
    }
    
    void DFS(int k, int fa, int have_fa){ 
            vis[k] = 1;
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(!to) continue ;
                    edge[i].to = edge[i^1].to = 0;
                    if(!vis[to]){ 
                            DFS(to, k, 1);
                            if(!use_fa[to]) A[k].pb(to); // to使用了与父亲k相连的边
                    }else A[k].pb(to);
            }
            if(have_fa) A[k].pb(fa);
            int size = A[k].size();
            if(size <= 1) return ;
            use_fa[k] = !(size & 1);
            for(reg int i = 0; i+1 < size; i += 2)
                    Ans[++ A_cnt][0] = A[k][i], Ans[A_cnt][1] = k, Ans[A_cnt][2] = A[k][i+1]; 
    
    }
    
    int main(){
            N = read(), M = read();
            num0 = 1;
            for(reg int i = 1; i <= M; i ++){
                    int u = read(), v = read();
                    Add(u, v), Add(v, u);
            }
            for(reg int i = 1; i <= N; i ++) if(!vis[i]) DFS(i, 0, 0);
            printf("%d
    ", A_cnt);
            for(reg int i = 1; i <= A_cnt; i ++) printf("%d %d %d
    ", Ans[i][0], Ans[i][1], Ans[i][2]);
            return 0;
    }
    
  • 相关阅读:
    火车进出站(POJ1363)
    字符串反转,栈模拟(ZOJ1151)
    模拟网页的浏览Stack(POJ1028)
    Codeforces Round #347 (Div.2)_B. Rebus
    Codeforces Round #347 (Div.2)_A. Complicated GCD
    BFS模板
    广搜破解密码(HDU1195)
    DFS+BFS(POJ3083)
    砍树,POJ(2665)
    快速幂取模,POJ(1995)
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822504.html
Copyright © 2011-2022 走看看