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还简单

  • 相关阅读:
    DataTables合并单元格(rowspan)的实现思路(多分组分类的情况)
    DataTables固定表格宽度(设置横向滚动条)
    用图片替代cursor光标样式
    DataTables获取指定元素的行数据
    任意表格(table)实现拖动列(column)改变列大小
    鼠标拖动改变DIV等网页元素的大小的最佳实践
    DataTables实现rowspan思路
    DataTables添加额外的查询参数和删除columns等无用参数
    击穿(强推---神仙代码)
    java jvm 参数 -Xms -Xmx -Xmn -Xss 调优总结
  • 原文地址:https://www.cnblogs.com/IltzInstallBI/p/12744235.html
Copyright © 2011-2022 走看看