设 G=(V,E) 是一个无向图,如果顶点集合 V 可分割为两个互不相交的子集 (A,B),并且每条边 (i,j)∈E 的两个端点 i 和 j 分别属于这两个不同的顶点子集,则称图 G 为一个二分图。
现在给定一棵树 T,要求选择树中两个没有边相连的结点 i 和 j,使得将无向边 (i,j) 加进 T 后能够构成二分图。你的任务是计算满足这个要求的选择方案有多少种。
输入格式:
输入第一行给出一个正整数 N (2≤N≤106),表示树中结点的个数。
接下来 N−1 行,每行给出树中一条边的两端结点编号,以空格分隔。结点编号从 1 开始。题目保证输入给出的是一棵树中所有的边。
输出格式:
在一行中输出方案数。注意:连接 (1,2) 和 (2,1) 视作同一个方案。
输入样例:
7
1 2
2 3
2 4
2 5
2 6
4 7
输出样例:
4
一、分析
1.求出给出图的二分两个集合的点数量,m和n-m,则可选方案为m*(m-n)-已有的边数(n-1)
2.如何求m:用染色法可以发现点会染成两中颜色,直接按颜色数
3.注意m为LL int ,否则答案部分WA
#include<bits/stdc++.h>
using namespace std;
long long int n,m;
const int N=1e6+10,M=N*2;
int head[N],e[M],ne[M],idx;
bool iscol[N];
int color[N];
//求原始二分图每个集合的点数 m n-m
//可添加的最大边数 sum=m*(n-m)-现有的边数n-1
void add(int a,int b)
{
e[idx]=b;
ne[idx]=head[a];
head[a]=idx;
idx++;
}
int dfs(int u,int col)
{
iscol[u]=true;
color[u]=col;
if(col==1) m++;
for(int i=head[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!iscol[j]) {
if(!dfs(j,3-col)) return 0;
}
else if(color[j]==col) return 0;
}
return 1;
}
int main()
{
cin>>n;
memset(head,-1,sizeof head);
for(int i=1;i<=n-1;++i)
{
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
int flag;
for(int i=1;i<=n;++i)
{
if(!iscol[i]) color[i]=1,flag=dfs(i,1);
if(!flag) break;
}
if(flag) cout<<m*(n-m)-(n-1)<<endl;
else cout<<0;
system("pause");
return 0;
}