您的位置:首页 > 其它

BestCoder Round #73 (div.2)(B)并查集

2016-02-20 22:10 513 查看


Rikka with Graph

Accepts: 123

Submissions: 525

Time Limit: 2000/1000 MS (Java/Others)

Memory Limit: 65536/65536 K (Java/Others)

问题描述
众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:

给出一张 nn 个点 n+1n+1 条边的无向图,你可以选择一些边(至少一条)删除。

现在勇太想知道有多少种方案使得删除之后图依然联通。

当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?

输入描述
第一行一个整数表示数据组数 T(T \leq 30)T(T≤30)。

每组数据的第一行是一个整数 n(n \leq 100)n(n≤100)。

接下来 n+1n+1 行每行两个整数 u,vu,v 表示图中的一条边。

输出描述
对每组数据输出一行一个整数表示答案。

输入样例
1
3
1 2
2 3
3 1
1 3

输出样例
9


题解:他只给你(N+1)条边,而形成一个联通图至少需要(N-1)条边,那么多出来的2条边只需要双重循环枚举删除2条边的各种可能性就好了,使用并查集维护点的关系,这里如果出现多棵树的根,那么就一定不是联通图,这里还是说一下,枚举从自己开始枚举,就是删除一条边的情况与删除2条边的情况

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<utility>
using namespace std;
vector<pair<int,int>>v;
#define N 105
int fa
;

int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void unio(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x!=y)
		fa[x]=y;
}
int solve(int x,int y,int n)
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
	}
	for(int i=0;i<=n;i++)
	{
		if(i==x||i==y)
			continue;
		unio(v[i].first,v[i].second);
	}
	int num=0;
	for(int i=1;i<=n;i++)
	{
		if(fa[i]==i)
			num++;
	}
	return num>1?0:1;
}
int main()
{
#ifdef CDZSC
	freopen("i.txt","r",stdin);
#endif
	int n,y,x,t;
	scanf("%d",&t);
	while(t--)
	{
		int ans=0;
		v.clear();
		scanf("%d",&n);
		for(int i=0;i<=n;i++)
		{
			scanf("%d%d",&x,&y);
			v.push_back(make_pair(x,y));
		}
		for(int i=0;i<=n;i++)
		{
			for(int j=i;j<=n;j++)
			{
				ans+=solve(i,j,n);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: