icpc:problems:usaco20feb_clock_tree_s
目录
problems | |
---|---|
名称 | Clock Tree S |
题目编号 | USACO20FEB_S3 |
题目链接 | luogu.com.cn/… |
来源 | USACO |
算法分类 | 树, 思维, 贪心 |
难易程度 | 一般般 |
Clock Tree S
想法
由于$N \le 2500$, 故该题目可使用$O(n^2)$方法。
该题目为一棵树,且定义每次往下访问时入度的点,时钟会增加。考虑对于叶子节点来说,只有通过父节点与自身来回走动才能达到$12$。假设所有的子树均会回到自身的父节点,故为了完成子节点变成12的任务,父节点会增加 $(12 - t[v])$ 次时钟旋转。每一个父节点都要完成子节点变成$12$的任务,所以父节点会变成某一个值,当子节点全部变为12时,再交由父节点的父节点来处理父节点自身的时钟问题。
题目允许在树中的任意一个地方进行停留,故如果当根节点的时钟为$1$,说明存在一条路径使得牛走回了根节点,当这条路径去除后,所有节点均可为$12$。
所以枚举可以作为起点的根节点,每次递归模拟完后对根节点的时钟进行检查,当时钟为$0$或$1$时,说明该点可以作为起点。
代码实现
#include<cstdio> #include<cstring> const int N = 2510; struct node { int v, next; }; node edge[2*N]; int head[N], cnt, n; int line[N], temp[N]; void add_edge(int x, int y) { edge[++cnt].v = y; edge[cnt].next = head[x]; head[x] = cnt; return ; } void DFS(int x, int fa = -1) { for (int i=head[x]; ~i; i=edge[i].next) { int v = edge[i].v; if(v == fa)continue; DFS(v, x); temp[x] = (temp[x] + 12 - temp[v]) % 12; } return ; } int main() { memset(head, -1, sizeof(head)); int x, y; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &line[i]); for (int i = 1; i <= n-1; ++i) { scanf("%d %d", &x, &y); add_edge(x, y); add_edge(y, x); } int ans = 0; for (int i = 1; i <= n; ++i) { memcpy(temp, line, sizeof(line)); DFS(i); if(temp[i] == 0 || temp[i] == 1){ ans++; } } printf("%d", ans); return 0; }
/app/www/public/data/pages/icpc/problems/usaco20feb_clock_tree_s.txt · 最后更改: 2023/06/10 12:33 由 温婕莺