zoukankan      html  css  js  c++  java
  • 「BalticOI 2020」村庄 (贪心)

    「BalticOI 2020」村庄

    Subtask1: Min

    考虑链上的情况,最优解肯定是两两相邻的交换,如果还有多,就再多交换一次

    因此树上的也是类似,实际上就是求解一个最小边覆盖问题,选择一条边就是交换边两端的点编号

    可以(O(n))贪心/dp求解树上最小边覆盖

    [ ]

    Subtask2: Max

    考虑理想的最优情况:对于任意一条边,我们要求它被经过次数尽可能多

    如果这条边两端子树大小分别为(a,b),则它被经过的最多次数显然是(2min{a,b})

    考虑找到树的重心,以它为根,此时任意一颗真子树的大小(leq frac{n}{2})

    为了构造最优答案,只需要每棵子树的集合相互错开即可

    一种简单的构造方法是:取( ext{dfs})序,平移(frac{n}{2})即可得到解

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    
    char IO;
    int rd(){
    	int s=0;
    	while(!isdigit(IO=getchar()));
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return s;
    }
    
    const int N=1e5+10,INF=1e9+10;
    
    int n;
    vector <int> G[N];
    ll Min,Max;
    int ans1[N],ans2[N];
    int dep[N],fa[N],vis[N];
    // 最小边覆盖贪心法
    void pre_dfs(int u,int f){ 
    	ans1[u]=u,fa[u]=f;
    	for(int v:G[u]) if(v!=f) {
    		pre_dfs(v,u); 
    		if(!vis[v]) vis[v]=vis[u]=1,swap(ans1[u],ans1[v]),Min+=2;
    	}
    	if(!vis[u] && !f) vis[u]=1,swap(ans1[u],ans1[G[u][0]]),Min+=2;
    }
    
    int A[N],C;
    int mi=1e9,rt,sz[N];
    // 找重心
    void dfs(int u,int f){
    	sz[u]=1;
    	int ma=0;
    	for(int v:G[u]) if(v!=f) {
    		dfs(v,u);
    		cmax(ma,sz[v]),sz[u]+=sz[v];
    		Max+=2*min(n-sz[v],sz[v]);
    	}
    	cmax(ma,n-sz[u]);
    	if(mi>ma) mi=ma,rt=u;
    }
    // 遍历dfs序
    void dfs_get(int u,int f) {
    	A[++C]=u;
    	for(int v:G[u]) if(v!=f) dfs_get(v,u);
    }
    int main(){
    	n=rd();
    	rep(i,2,n) {
    		int u=rd(),v=rd();
    		G[u].pb(v),G[v].pb(u);
    	}
    	pre_dfs(1,0),dfs(1,0),dfs_get(rt,0);
    	rep(i,1,n) ans2[A[i]]=A[(i+n/2-1)%n+1];
    	printf("%lld %lld
    ",Min,Max);
    	rep(i,1,n) printf("%d ",ans1[i]);
    	puts("");
    	rep(i,1,n) printf("%d ",ans2[i]);
    	puts("");
    }
    
  • 相关阅读:
    又见博弈
    两道来自CF的题
    温习及回顾
    笔试面试总结
    Python Cha4
    初学ObjectiveC
    设计模式汇总(三)
    转贴XML的写法建议
    让从Objec中继承的类也拥有鼠标事件
    关于异常处理的一些看法
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14517437.html
Copyright © 2011-2022 走看看