璟雯院

珺璟如晔,雯华若锦

用户工具

站点工具


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 由 温婕莺