Rikka with Graph
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 976 Accepted Submission(s): 451
Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:
Yuta has a non-direct graph with n vertices and n+1 edges. Rikka can choose some of the edges (at least one) and delete them from the graph.
Yuta wants to know the number of the ways to choose the edges in order to make the remaining graph connected.
It is too difficult for Rikka. Can you help her?
Yuta has a non-direct graph with n vertices and n+1 edges. Rikka can choose some of the edges (at least one) and delete them from the graph.
Yuta wants to know the number of the ways to choose the edges in order to make the remaining graph connected.
It is too difficult for Rikka. Can you help her?
Input
The first line contains a number
T(T≤30)
——The number of the testcases.
For each testcase, the first line contains a number n(n≤100) .
Then n+1 lines follow. Each line contains two numbers u,v , which means there is an edge between u and v.
For each testcase, the first line contains a number n(n≤100) .
Then n+1 lines follow. Each line contains two numbers u,v , which means there is an edge between u and v.
Output
For each testcase, print a single number.
Sample Input
1 3 1 2 2 3 3 1 1 3
Sample Output
9
Source
分析:该题目给了n+1条边,要保证连通最多删除两条边,即n个结点,最少需要n-1条边连通。
所以只需要枚举删除其中一条边是否连通和删除其中两条边是否连通,时间复杂度是O(n^3),判断无向图连通用到并查集。
代码如下:
#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct node{
int u,v;
}Node;
int pre[110];
Node a[110];
int find(int x)
{//并查集
int r=x;
while(pre[r]!=r)
r=pre[r];
int i=x,j;
while(pre[i]!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
bool merge(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy)
{
pre[fx]=fy;
return true;
}
return false;
}
int main()
{
int T,n;
int i,j,k;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int count=0;
for(i=0;i<=n;i++)
scanf("%d %d",&a[i].u,&a[i].v);
//枚举寻找删除一条边是否连通
for(i=0;i<=n;i++)
{
int con = n;
for(j=1;j<=n;j++)
pre[j]=j;
for(j=0;j<=n;j++)
{
if(j!=i && merge(a[j].u,a[j].v))
con--;
}
if(con==1)
count++;
}
//枚举寻找删除两条边是否连通
for(k=0;k<=n;k++)
{
for(i=k+1;i<=n;i++)
{
int con = n;
for(j=1;j<=n;j++)
pre[j]=j;
for(j=0;j<=n;j++)
{
if(j!=i && j!=k && merge(a[j].u,a[j].v))
con--;
}
if(con==1)
count++;
}
}
printf("%d\n",count);
}
return 0;
}