2020寒假【gmoj2412】【clocktree】【DFS+邻接表】

48 篇文章 0 订阅
43 篇文章 0 订阅

题目描述

Farmer John 的新牛棚的设计十分奇怪:它由编号为 1…N 的 N 间房间(2≤N≤2500),以及 N−1 条走廊组成。每条走廊连接两间房间,使得每间房间都可以沿着一些走廊到达任意其他房间。
牛棚里的每间房间都装有一个在表盘上印有标准的整数 1…12 的圆形时钟。然而,这些时钟只有一根指针,并且总是直接指向表盘上的某个数字(它从不指向两个数字之间)。
奶牛 Bessie 想要同步牛棚中的所有时钟,使它们都指向整数 12。然而,她头脑稍有些简单,当她在牛棚里行走的时候,每次她进入一间房间,她将房间里的时钟的指针向后拨动一个位置。例如,如果原来时钟指向 5,现在它会指向 6,如果原来时钟指向 12,现在它会指向 1。如果 Bessie 进入同一间房间多次,她每次进入都会拨动这间房间的时钟。
请求出 Bessie 可能的出发房间数量,使得她可以在牛棚中走动并使所有时钟指向 12。注意 Bessie 并不拨动她出发房间的时钟,但任意时刻她再次进入的时候会拨动它。时钟不会自己走动;时钟只会在 Bessie 进入时被拨动。此外,Bessie 一旦进入了一条走廊,她必须到达走廊的另一端(不允许走到一半折回原来的房间)。

输入

输入的第一行包含 N。下一行包含 N 个整数,均在范围 1…12 之内,表示每间房间初始时的时钟设置。以下 N−1 行每行用两个整数 a 和 b 描述了一条走廊,两数均在范围 1…N 之内,为该走廊连接的两间房间的编号。

输出

输出出发房间的数量,使得 Bessie 有可能使所有时钟指向 12。

样例输入

4
11 10 11 11
1 2
2 3
2 4

样例输出

1
数据范围限制

测试点 1-7 满足 N≤100。
测试点 8-15 没有额外限制。

提示

在这个例子中,当且仅当 Bessie 从房间 2 出发时她可以使所有房间的时钟指向 12(比如,移动到房间 1,2,3,2,最后到 4)。

分析

这道题我们可以每次去枚举一个房间 i 作为根,并去更新与它相连的房间。既然题目中是验证是否能完成,我们不妨贪心地看,每次不停地从父子之间来回走,直到把孩子改成12,这时候根据父子差固定,我们就能知道u现在是多少。然后再去搞下一个孩子,再确定u的值。直到把所有孩子都改好,此时u固定到了某个数。回到上一层,再由父亲把 u 改成12。
那么这么一轮下来,最后除了根,其他点都是12了。那么根如果正好是12,说明是可以的。如果根不是12呢?其实根是1也行,因为这样就最后的时候从根的最后一个孩子停下,不走回来。这时候根和最后一个孩子的时间会差一个。除了这两种情况,其他都不行。
if(edge[i].y==v) continue;
一定要加这一句,否则会死循环
因为:题目规定两两房间之间是双向边,所以对于任意一个点,它的儿子也是它的爸爸,但是我们规定了只由一个点当根!!

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,a[5000],tot,t[5000],h[5000],ans;
struct node
{
	int x,y,next;
}b[5000];
void add(int xx,int yy)//邻接表 
{
	tot++;
	b[tot].x=xx;
	b[tot].y=yy;
	b[tot].next=h[xx];
	h[xx]=tot;
}
void dfs(int u,int v)
{
	for(int i=h[u];i;i=b[i].next)
	{
		if(b[i].y==v) continue;
		dfs(b[i].y,u);
		t[u]=(t[u]-t[b[i].y]+12)%12;
	}
} 
int main()
{
    freopen("clocktree.in","r",stdin);
    freopen("clocktree.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
    	a[i]%=12;//如果是12的话变成0 
	}
	int x,y;
	for(int i=1;i<=n-1;i++)
	{
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
	{
		memcpy(t,a,sizeof(t));//百度找的,把a的所有东西复制到t里面
		dfs(i,0);//枚举根 
		if(t[i]==0||t[i]==1) ans++;//走一圈之后根是0或1都可以,是0就停下,是1就踩上去 
	}
	cout<<ans; 
    fclose(stdin);
    fclose(stdout);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值