HDU5631——Rikka with Graph

3 篇文章 0 订阅
1 篇文章 0 订阅

Rikka with Graph

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1066    Accepted Submission(s): 520



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?
 

Input
The first line contains a number T(T30) ——The number of the testcases.

For each testcase, the first line contains a number n(n100) .

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
 

解:保证联通至少需要n-1条边,所以可以删除一条边或者两条边,因数据不大直接暴力。借用并查集来判断是否联通。
#include<stdio.h>
#include<string.h>
struct p{
	int x;
	int y;
}a[110];//存储边 

int pre[105];//存储 父节点(当时讲的掌门) 

void init(int n)  //初始化函数假设自己的父节点都是自己 
{  
    for(int i=1; i<=n; i++)  
    {  
        pre[i] = i;  
    }  
}
//查询x的最终父节点。如果x的父节点不是自己,就一直向上找,找到最终的父节点   
int find(int x){ 
	if(x!=pre[x]){
		return pre[x]=find(pre[x]); 
	} 
	return x;
}
//将节点连接,两个节点的父节点不同就强迫x的父节点为y(可以倒过来) 
void mix(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy){
		pre[fx]=fy;
	}
}
int main(){
	int t,n;
	scanf("%d",&t);
	while(t--){
		int count=0;
		scanf("%d",&n);
		for(int i=1;i<=n+1;i++){
			scanf("%d%d",&a[i].x,&a[i].y);
		}
		//以上是标准输入
		//删除一条边的时候 
		for(int i=1;i<=n+1;i++){
			init(n);
			//将剩余的边进行加到 
			for(int j=1;j<=n+1;j++){
				if(i!=j){
					mix(a[j].x,a[j].y);
				}
			}
			//判断满足条件 
			int flag=0;
			for(int k=1;k<=n;k++){
				if(pre[k]==k){
					flag++;
				}
			} 
			if(flag==1){
				count++;
			}
		}
		//删除两条边(循环我应该是写多了几次) 
		for(int z=1;z<=n+1;z++){
			for(int i=z+1;i<=n+1;i++){ 
			//每次必须重新赋值否则数据出现混乱 
				init(n);
				for(int j=1;j<=n+1;j++){
					if(i!=j && z!=j){
						mix(a[j].x,a[j].y);
					}
				}
				//判断父亲是否一致,一致则满足条件 
				int flag=0;//用来标记数组中的数字种类,一种则代表满足条件 
				for(int k=1;k<=n;k++){
					if(pre[k]==k){
						flag++;
					}
				} 
				if(flag==1){
					count++;
				}
				
			}
		}
		printf("%d\n",count);
	}	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值