题解【2.23考试T1】div

1. div
【题目描述】
  这是一道传统题,源代码的文件名为 div.cpp/c/pas。
  给定一棵树,你要判断是否存在一条边,使得割掉这条边后,这棵树被分成了点数相等的两部分,并且如果存在,请你找到这条边。
【输入格式】
  从 div.in 中读入。
  第一行,一个正整数 n。
  接下来 n-1 行描述树的形态,每行两个空格隔开的正整数 u 和 v,表示树中有一条连接 u 号点和 v 号点的边。保证数据合法。
【输出格式】
  输出到 div.out 中。
  仅一行,一个正整数 ans 表示要割掉给出的第 ans 条边。如果不存在这样的边,输出-1。
【输入样例 A】
4
1 2
2 3
3 4
【输出样例 A】
2
【输入样例 B】
8
1 2
2 3
2 4
1 5
5 6
5 7
5 8
【输出样例 B】
4
【评分标准】
对于 40%的数据,n<=100;
对于另 40%的数据,树退化为链;
对于 100%的数据,n<=100,000。
时间限制 1s,空间限制 512MB。

题解:

  我们可以先判断n是否为奇数。如果是,就直接输出-1(因为任意奇数都不能平分成两个整数相加)。

  然后,我们可以用dfs 求出每个子树的大小,找到一个大小恰为总点数一半的子树即可。

  代码(std):

 1 #include <bits/stdc++.h>
 2 #define rep(i,l,r) for(int i=l;i<=r;i++)
 3 #define per(i,r,l) for(int i=r;i>=l;i--)
 4 #define N 100005
 5 int n,x,y,ans,sz[N];
 6 std::vector<std::pair<int,int> > e[N];
 7 void dfs(int pre,int x)
 8 {
 9     sz[x]=1;
10     rep(i,1,e[x].size())
11     {
12         int y=e[x][i-1].first;
13         if(y==pre) continue;
14         dfs(x,y);
15         sz[x]+=sz[y];
16         if(sz[y]*2==n) ans=e[x][i-1].second;
17     }
18 }
19 int main()
20 {
21     char fni[]="div.in",fno[]="div.out";
22     freopen(fni,"r",stdin);
23     freopen(fno,"w",stdout);
24     scanf("%d",&n);
25     rep(i,1,n) e[i].clear();
26     rep(i,1,n-1)
27     {
28         scanf("%d%d",&x,&y);
29         e[x].push_back(std::make_pair(y,i));
30         e[y].push_back(std::make_pair(x,i));
31     }
32     ans=-1;
33     dfs(0,1);
34     printf("%d\n",ans);
35     fclose(stdin);
36     fclose(stdout);
37 }

猜你喜欢

转载自www.cnblogs.com/xsl19/p/10424122.html