寒假总结 1-20

遍历问题 - 洛谷

自己画图半天才整明白

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
int main()
{
	char q[100],h[100];
	scanf("%s",q);scanf("%s",h);
	int l=strlen(q);
	int end=1;
	for(int i=0;i<l-1;i++){
		for(int j=1;j<l;j++){
			if(q[i]==h[j]&&q[i+1]==h[j-1]){
				end*=2;
			}
		}
	}
	printf("%d",end);
	return 0;
}
//只需要寻找只有单个字节点的节点
//先序为父左右,后序为左右父
//如果夫只有一个字,则一定是父子:子父
//无论先序还是后序都不能将其分离

【模板】并查集 - 洛谷

初版代码,直接题解有三个代码超时,开O2能过

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>

int num[100010]={0};

int main()
{
	int n,t;
	scanf("%d%d",&n,&t);
	for(int i=1;i<=n;i++) num[i]=i;
	int tip,x,y;
	for(int ok=0;ok<t;ok++){
//		printf("%d\n",ok);
//		printf("\nsr:");
		scanf("%d%d%d",&tip,&x,&y);
//		printf("\n");
		if(tip==1){
			int a=x,b=y;
			while(a!=num[a])a=num[a];
			while(b!=num[b])b=num[b];
			num[b]=a;
		}
		else{
			int a=x,b=y;
			while(a!=num[a])a=num[a];
			while(b!=num[b])b=num[b];
			if(a==b) printf("Y\n");
			else printf("N\n");
		}
//		printf("*%d\n",ok);
//		for(int i=1;i<=n;i++) printf("%d ",num[i]);
//		printf("\n");
	}
	return 0;
}

看了洛谷题解的递归方法,发现可以把多代关系都压成一代,31ms过了

如果a有上一代集合,用c标记num[a]的位置(这一代),a=num[a]去找上一代,而num[c](原来的num[a])改成num[a]相当于向上一代移动一个位置

把
while(a!=num[a])a=num[a];
替换为
while(a!=num[a]){
	int c=a;a=num[a];num[c]=num[a];
}

b同理

亲戚 - 洛谷

稍微改一下就并查集模板就出来了(吃个饭就忘记模板了,想半天才ac)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>

int num[100010]={0};

int main()
{
	int n,m,p;
	scanf("%d%d%d",&n,&m,&p);
	for(int i=1;i<=n;i++) num[i]=i;
	int a,b;
	for(int i=0;i<m;i++){
		scanf("%d%d",&a,&b);
		int x=a,y=b;
		while(x!=num[x]){
			int c=x;x=num[x];num[c]=num[x];
		}
		while(y!=num[y]){
			int c=y;y=num[y];num[c]=num[y];
		}
		num[y]=x;
	}
	for(int i=0;i<p;i++){
		scanf("%d%d",&a,&b);
		int x=a,y=b;
		while(x!=num[x])x=num[x];
		while(y!=num[y])y=num[y];
		if(x==y) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

朋友 - 洛谷

写这个题目的时候才注意到做前面两个并查集没有注意节点与上一代的大小关系,而这个题目开始强调相互间的大小关系

for(int i=0;i<p;i++){
		scanf("%d%d",&x,&y);
		a=x,b=y;
		while(a!=man[a]){
			c=a;a=man[a];man[c]=man[a];
		}
		while(b!=man[b]){
			c=b;b=man[b];man[c]=man[b];
		}
		man[b]=man[a];
	}

原来的代码段,假设输入1,2和 3,1

数组的值首先变为1,1,3

再变为                 3,1,3

如果是要求所有节点最后的关联节点为1,就不符合题意了

(其实写的时候可以改成如果关联节点最后等于man[1]应该也可以)

加上比较两边各自的人数之后就过了

if(man[b]>man[a]) man[b]=man[a];
else man[a]=man[b];

ac代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>


int man[20010]={0},wuman[20010]={0};
int main()
{
	int n,m,p,q;
	scanf("%d%d%d%d",&n,&m,&p,&q);
	for(int i=0;i<=n;i++) man[i]=i;
	for(int i=0;i<=m;i++) wuman[i]=i;
	int a,b,c,x,y;
	for(int i=0;i<p;i++){
		scanf("%d%d",&x,&y);
		a=x,b=y;
		while(a!=man[a]){
			c=a;a=man[a];man[c]=man[a];
		}
		while(b!=man[b]){
			c=b;b=man[b];man[c]=man[b];
		}
		if(man[b]>man[a]) man[b]=man[a];
		else man[a]=man[b];
	}
	for(int i=0;i<q;i++){
		scanf("%d%d",&x,&y);
		a=-x,b=-y;
		while(a!=wuman[a]){
			c=a;a=wuman[a];wuman[c]=wuman[a];
		}
		while(b!=wuman[b]){
			c=b;b=wuman[b];wuman[c]=wuman[b];
		}
		if(wuman[b]>wuman[a]) wuman[b]=wuman[a];
		else wuman[a]=wuman[b];
	}
	int op=1,ed=1;
	for(int i=2;i<=n;i++){
		a=i;
		while(a!=man[a]) a=man[a];
		if(a==1) op++;
	}
	for(int i=2;i<=m;i++){
		a=i;
		while(a!=wuman[a]) a=wuman[a];
		if(a==1) ed++;
	}
	printf("%d",op<ed?op:ed);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值