zoukankan      html  css  js  c++  java
  • CF1103C Johnny Solving(构造题)

    洛谷传送门


    解题思路

    在图上很难做这种构造题,所以一种常用的方法是求出其生成树

    生成树上做就容易很多。

    于是这个题就按照 dfs 序建立一颗生成树,记录下每个节点的返祖边。

    于是第一问可以根据树的深度判断是否符合要求,符合的话直接输出。

    若没有,则易证第二问一定成立:

    因为第一问不成立,所以叶子节点数一定 (geqslant k),而题中保证每个节点的度数 (geqslant3),也就暗示了叶子节点都有 (geqslant2) 条返祖边。

    所以一定能从每个叶子节点找到一个符合要求的环。

    假设叶子节点 k 的两个返祖祖先为 x 和 y,则通过作差法易证:

    ((dep[u]-dep[x]+1))((dep[u]-dep[y]+1))((dep[y]-dep[x]+2)) 中至少有一个不是 (3) 的倍数。

    判断一下输出即可。

    注意

    数组一定要开够:大小为 m 的两倍!否则会在第四个点TLE。

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int maxn=5e5+5;
    int n,m,k,cnt,cnt_leaf,leaf[maxn],p[maxn],dep[maxn],fa[maxn],ancestor[maxn][105];
    int maxdep,ed;
    template <typename T>
    inline void read(T &x)
    {
        char c;
        x=0;
        int fu=1;
        c=getchar();
        while(c>57||c<48){
            if(c==45){
            	fu=-1;
            }
            c=getchar();
        }
        while(c<=57&&c>=48)
        {
            x=(x<<3)+(x<<1)+c-48;
            c=getchar();
        }
        x*=fu;
    }
    struct node{
    	int v,next;
    }e[maxn*2];
    void insert(int u,int v){
    	cnt++;
    	e[cnt].v=v;
    	e[cnt].next=p[u];
    	p[u]=cnt;
    }
    void dfs(int u,int f,int deep){
    	dep[u]=deep;
    	if(dep[u]>maxdep){
    		maxdep=dep[u];
    		ed=u;
    	}
    	fa[u]=f;
    	leaf[++cnt_leaf]=u;
    	for(int i=p[u];i!=-1;i=e[i].next){
    		int v=e[i].v;
    		if(v==f) continue;
    		if(dep[v]){
    			ancestor[u][++ancestor[u][0]%100]=v;
    			continue;
    		}
    		if(leaf[cnt_leaf]==u) cnt_leaf--;
    		dfs(v,u,deep+1);
    	}
    }
    void print(int u,int to){
    	printf("%d ",to);
    	if(u==to) return;
    	print(u,fa[to]);
    }
    int main(){
    	memset(p,-1,sizeof(p));
    	read(n);
    	read(m);
    	read(k);
    	for(int i=1;i<=m;i++){
    		int u,v;
    		read(u);
    		read(v);
    		insert(u,v);
    		insert(v,u);
    	} 
    	dfs(1,-1,1);
    	if(maxdep>=(n-1)/k+1){
    		puts("PATH");
    		printf("%d
    ",maxdep);
    		while(ed!=-1){
    			printf("%d ",ed);
    			ed=fa[ed];
    		}
    		return 0;
    	}
    	puts("CYCLES");
    	for(int i=1;i<=k;i++){
    		int u=leaf[i],x=ancestor[u][1],y=ancestor[u][2];
    		if(dep[x]>dep[y]) swap(x,y);
    		if((dep[u]-dep[x]+1)%3!=0){
    			printf("%d
    ",dep[u]-dep[x]+1);
    			print(x,u);
    			puts("");
    		}else{
    			if((dep[u]-dep[y]+1)%3!=0){
    				printf("%d
    ",dep[u]-dep[y]+1);
    				print(y,u);
    				puts("");
    			}else{
    				printf("%d
    %d ",dep[y]-dep[x]+2,u);
    				print(x,y);
    				puts("");
    			}
    		}
    	}
        return 0;
    }
    
  • 相关阅读:
    07.15 first与first-child的区别
    7.15 css与js 选择奇偶子元素的区别
    7.15过有意思的生活
    7.14养成健身习惯
    8080端口被占用
    Vue自定义指令和认识钩子函数
    按键修饰符
    Vue 的过滤器
    列表渲染
    在Vue中使用.class样式
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15321926.html
Copyright © 2011-2022 走看看