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 ",ans); 35 fclose(stdin); 36 fclose(stdout); 37 }