题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5631
1 3 1 2 2 3 3 1 1 3
9
众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的: 给出一张 n 个点 n+1 条边的无向图,你可以选择一些边(至少一条)删除。 现在勇太想知道有多少种方案使得删除之后图依然联通。 当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?
第一行一个整数表示数据组数 T(T≤30)。 每组数据的第一行是一个整数 n(n≤100)。 接下来 n+1 行每行两个整数 u,v 表示图中的一条边。
对每组数据输出一行一个整数表示答案。
1 3 1 2 2 3 3 1 1 3
9
采用并查集的方法进行判断是否连通。由于点和边都很少,所以就可以直接暴力。删一条边并查集一次,删两条边并查集一次。
最后判断所有的点是否在一棵树上,就可以统计有多少种方法了。
详见代码。
#include <iostream> #include <cstdio> using namespace std; struct node { int u,v; } s[110]; int fa[110],n; void init() { for (int i=1; i<=n; i++) fa[i]=i; } int Find(int x) { if (x!=fa[x]) return fa[x]=Find(fa[x]); return x; } void Union(int x,int y) { x=Find(x); y=Find(y); if (x!=y) fa[x]=y; } int main() { int t; scanf("%d",&t); while (t--) { int sum=0; scanf("%d",&n); for(int i=1; i<=n+1; i++) { scanf("%d%d",&s[i].u,&s[i].v); } //删一条边 for (int i=1; i<=n+1; i++) //假设把第i条边删掉 { init(); for (int j=1; j<=n+1; j++) { if (j==i) continue; Union(s[j].u,s[j].v); } int flag=0; for(int k=1; k<=n; k++) //判断是否只有一个父亲结点 { if (fa[k]==k) flag++; } if (flag==1) sum++; } //删两条边 for (int i=1; i<=n+1; i++) { for (int j=i+1; j<=n+1; j++) { init(); for (int k=1; k<=n+1; k++) { if (i==k||j==k) continue; Union(s[k].u,s[k].v); } int flag=0; for(int k=1; k<=n; k++) //判断是否只有一个父亲结点 { if (fa[k]==k) flag++; } if (flag==1) sum++; } } printf ("%d\n",sum); } return 0; }