poj 并查集 - 1308 Is It A Tree?

最近因为保研,在刷一些poj上面的ACM题,发现智商真的是无限被碾压。。。


1308 这一道题目考察的是并查集,并查集题目,并的意思就是将两个不同类别的集合合并到一起,类似于两棵树合并;查的意思就是找到这个点所属集合的根节点。基本上并查集题目都是在大体架构上面加一些东西即可。并查集代码模板在这里点击打开链接


并查集的基本模板:

int pre[1000 ];
int find(int x)  //查找根节点
{ 
    int r=x;
    while ( pre[r ] != r )  //返回根节点 r
          r=pre[r ];
 
    int i=x , j ;
    while( i != r )  //路径压缩
    {
         j = pre[ i ]; // 在改变上级之前用临时变量  j 记录下他的值 
         pre[ i ]= r ; //把上级改为根节点
         i=j;
    }
    return r ;
}
 
 
void join(int x,int y) /判断x y是否连通,
                      //如果已经连通,就不用管了 //如果不连通,就把它们所在的连通分支合并起,
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
        pre[fx ]=fy;
}

上面是并查集的并查操作,也是最基本的模板,一般情况下我们只需要加入一些记录数组或者判断变量,就可以很快做出并查集的题目。

好了,现在开始讨论这道题目。

这道题目有三个判断是否是树的地方:

1. 为空节点(一开始就是0 0 )

2. 当前两个节点的根结点是不是一个,(也就是没有出现了5-3-8,5-6 ,这是两个节点是6 8的情况。)

3. 最后没有独立节点在树外(最后判断所有点的根结点是否一样)


如果满足了这三点,这个就是一个树,反之不是。所以我们加一个ranks数组记录所有被提到的点,main函数中加一个tree的布尔值来判断是否这一个例子是否是树。基本架构还是并查集的模板。

#include <iostream>  
using namespace std;  
  
const int MAXN = 105; 
int pa[MAXN];   
int ranks[MAXN];   

  
void make_set()  
{/*创建一个单元集*/  
	int x;
	for(x=0;x<100;x++){
    pa[x] = x;  
    ranks[x] = 0; 
	}
}  
  
int find_set(int x)  
{/*带路径压缩的查找*/
/*保存待查找的数*/
int r = x, temp;  
/*找到根节点*/
while(pa[r] != r) r = pa[r];  
while(x != r)  
    {  
        temp = pa[x];  
        pa[x] = r;  
        x = temp;  
    }  
return x;  
}  

void union_set(int x, int y)  
{  
		x = find_set(x);  
		y = find_set(y);  
	if(x == y)return ;  
	pa[y]=x;
}  
  
   
int main()  
{  
    int  x, y, i,temp,size=1;
	make_set();
	while(1){
		scanf("%d %d",&x,&y);
		if(x==-1 && y==-1)break;
		if(x==0 && y==0){
			printf("Case %d is a tree.\n",size++);
			continue;
		}
		make_set();
		ranks[x] = ranks[y] = true;
		bool tree = true;
		temp=x;
		if(x==y)	tree = false;
		else union_set(x,y);
		while(scanf("%d %d",&x,&y) && x!=0){
			ranks[x] =ranks[y]=true;
			if(find_set(x)==find_set(y)) tree = false;
			union_set(x,y);
			
		}
		for(i=1;i<100;i++){
			if(ranks[i]&& find_set(i)!= find_set(temp)){
				tree= false;
			}
		}
		if(tree) printf("Case %d is a tree.\n", size ++);
        else printf("Case %d is not a tree.\n", size ++);
	}
		
   
    return 0;  
}  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ - 3616是一个题目,题目描述如下: 给定一组区间,每个区间有一个权重,要求选择一些区间,使得这些区间的右端点都小于等于k,并且权重之和最大。请问最大的权重和是多少? 解决这个问题的思路是使用动态规划。首先,将区间按照左端点从小到大进行排序。然后,定义一个dp数组,dp[i]表示右端点小于等于i的所有区间所能得到的最大权重。 接下来,遍历每一个区间,对于每个区间i,将dp[i]初始化为区间i的权重。然后,再遍历i之前的每个区间j,如果区间j的右端点小于等于k,并且区间j的权重加上区间i的权重大于dp[i],则更新dp[i]为dp[j]加上区间i的权重。 最后,遍历整个dp数组,找到最大的权重和,即为所求的答案。 下面是具体的代码实现: ```cpp #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct interval{ int start, end, weight; }; interval intervals[10005]; int dp[10005]; int n, m, k; bool compare(interval a, interval b) { if (a.start == b.start) { return a.end < b.end; } else { return a.start < b.start; } } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp, 0, sizeof dp); for (int i = 0; i < m; i++) { scanf("%d %d %d", &intervals[i].start, &intervals[i].end, &intervals[i].weight); } sort(intervals, intervals + m, compare); for (int i = 0; i < m; i++) { dp[i] = intervals[i].weight; for (int j = 0; j < i; j++) { if (intervals[j].end <= k && dp[j] + intervals[i].weight > dp[i]) { dp[i] = dp[j] + intervals[i].weight; } } } int maxWeight = 0; for (int i = 0; i < m; i++) { maxWeight = max(maxWeight, dp[i]); } printf("%d\n", maxWeight); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值