zoukankan      html  css  js  c++  java
  • codeforces 1244D Paint the Tree 题解

    updated 2019.11.10 之前笔误了

    首先这题的条件就在于 一棵树上任意两个距离(leq2)的点颜色不同 并且只有三种颜色

    那么如果存一个点(u) 有三个点与(u)相连 这三个点颜色就必须两两不同
    然后这三个点就把三种颜色取完了
    然后(u)就没办法取颜色了 这样就无解

    于是 只要存在任意一个节点的度数(geq3)就无解

    然后我们发现这棵树是条链

    再看这个链 任意三个相连的节点都需要两两颜色不同
    所以任意三个相连的节点只要确定了两个 第三个就确定了 就可以一步一步推下去了
    一开始就随便找一条边 与这条边相连的两个点分别枚举选什么颜色(这两个点颜色不能相同) 然后一步一步往外推 记录下六种情况下答案最小的情况 就可以了

    放个图吧 好理解

    确定过程(枚举(col1)(col2) 这里随便找一条边都行 我找了((4,5))这条边)
    J8nVRP.png
    下面是无解情况
    J8nmM8.png

    记录下每个点在这种情况下(枚举6种情况)标记成什么颜色 然后直接全部加起来 统计答案

    这是考场代码 我都是直接dfs的 其实不用 但反正复杂度对的 无所谓

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <cmath>
    using namespace std;
    typedef long long LL;
     
    LL n,m,k;
    LL c[4][800005] = {0};
    LL ans = 0;
    string s;
     
    LL ec = 0,to[800005],nxt[800005],hed[200005] = {0};
    LL deg[400005] = {0};
    void add_edge(LL f,LL t){
    	++ ec; to[ec] = t; nxt[ec] = hed[f]; hed[f] = ec;
    	deg[t] ++;
    }
     
    LL col[200005] = {0};
    LL rec[200005] = {0};
     
    LL chg(LL x,LL y){
    	return 6 - x - y; // 小技巧 根据另外两点颜色确定该点颜色
    }
     
    void dfs(LL u,LL f,LL uc,LL fc){ // 标记颜色
    	for(LL i = hed[u];i;i = nxt[i]){
    		LL v = to[i];
    		if(v == f) continue;
    		col[v] = chg(uc,fc);
    		dfs(v,u,col[v],uc);
    	}
    }
     
    int main(){
    	LL a,b;
    	ios::sync_with_stdio(false);
    	cin >> n;
    	for(LL i = 1;i <= n;i ++) cin >> c[1][i];
    	for(LL i = 1;i <= n;i ++) cin >> c[2][i];
    	for(LL i = 1;i <= n;i ++) cin >> c[3][i];
    	
    	for(LL i = 1;i < n;i ++){
    		cin >> a >> b;
    		add_edge(a,b);
    		add_edge(b,a);
    	}
    	
    	for(LL i = 1;i <= n;i ++){
    		if(deg[i] >= 3){
    			cout << -1 << endl;
    			return 0;
    		}
    	}
    	LL ans = 0x3f3f3f3f3f3f3f3f;
    	for(LL c1 = 1;c1 <= 3;c1 ++){
    		for(LL c2 = 1;c2 <= 3;c2 ++){
    			if(c1 == c2) continue;
    			col[a] = c1; col[b] = c2; // 随便找一条边 枚举
             // 我在这里直接用了最后输入的那条边
    			dfs(a,b,c1,c2);
    			dfs(b,a,c2,c1);
            // 注意要从两个点两个方向 都要dfs 
    			LL cnt = 0;
    			for(LL i = 1;i <= n;i ++) cnt += c[col[i]][i];
    			if(cnt < ans){
    				ans = cnt;
    				for(LL i = 1;i <= n;i ++) rec[i] = col[i]; // 记录答案
    			}
    		}
    	}
    	cout << ans << endl;
    	for(LL i = 1;i <= n;i ++) cout << rec[i] << (i == n ? '
    ' : ' '); 
    	return 0;
    }
    

    顺带一提 这场CF的D比C还简单

  • 相关阅读:
    突然想谈谈——我的软件测试入门
    js+rem动态计算font-size的大小,适配各种手机设备!
    iOS 如何打测试包,直接给测试人员使用(绝对的新手入门)
    去掉无用的多余的空格(string1.前后空格,2.中间空格)
    iOS 自定义键盘ToolBar(与键盘的弹出、收起保持一致)
    iOS上线...踩坑
    iOS10 导航条,这个二狗子变了...踩坑
    ios程序发布测试打包
    获取毫秒级时间戳
    弹簧动画效果(系统自带方法)
  • 原文地址:https://www.cnblogs.com/IltzInstallBI/p/12744235.html
Copyright © 2011-2022 走看看