bjfu_Algorithm Design and Analysis-Experiment 6

7 Advanced Data Structure

Binary Tree
描述
Given the preorder sequence and inorder sequence of a binary tree, can you find out its postorder sequence?
输入
The first line is an integer N (1<=N<=1000), the number of vertices of the binary tree. The next two lines indicate the preorder sequence and inorder sequence of the binary tree respectively. The inputs terminate at the end of file.

输出
For each test case, print the postorder sequence of the binary tree. There will be a blank after every number.
输入样例 1
9
1 2 4 7 3 5 8 9 6
4 7 2 1 8 5 9 3 6
输出样例 1
7 4 2 8 9 5 6 3 1

题目大概就是输入二叉树的前序和中序,然后输出他的后序,注意每个输出后面都要有空格,最后一个换行。

#include <stdio.h>
#include<string.h>
const int N=1000;
int s1[N], s2[N], ans[N];//s1[N],s2[N]分别为先序和中序遍历序列,ans[N]为后序输出序列
void build(int n, int* s1, int* s2, int* s)//构造二叉树
{
	if(n <= 0) return;//为根时结束
	int p = strchr(s2, s1[0]) - s2;//找到根结点的位置
	//strchr()函数:
	//在参数str所指向的字符串中搜索第一次出现字符c(一个无符号字符)的位置。
	build(p, s1+1, s2, s);//递归构造左子树的后序遍历
	build(n-p-1, s1+p+1, s2+p+1, s+p);//递归构造右子树的后序遍历
	s[n-1] = s1[0];//把根结点添加到最后
}
int main()
{
	while(scanf("%d%d",s1, s2) == 2)
	{
		int n= strlen(s1);
		build(n, s1,s2, ans);
		ans[n] = '\0';
		printf("%d\n",ans);
		return 0;
	}
}

上述代码参考了这个博主

Groups
描述
Xiao Ming is an art teacher. In a handicraft class, he wants to divide students into groups. For the group with the fewest students, he will help them complete the task. However, he only knows that student Si and Sj are in the same group. Can you help Xiao Ming find the group with the fewest students?
输入
The first line is an integer T (T<50), the number of the test cases. For each test case, the first line are two integers N and M (1<=N, M<=1000). N is the number of students in Xiao Ming’s class, and M is the number of pairs. Then M lines follow. Each line contains two integers Ai and Bi, meaning that students Ai and Bi are in the same group.
输出
For each test case, print the number of students in the group including the fewest students.


描述
小明是一位美术老师。在手工课上,他想把学生分成小组。对于学生最少的小组,他将帮助他们完成任务。然而,他只知道学生Si和Sj在同一组。你能帮小明找到学生最少的那一组吗?
输入
第一行是一个整数T(T<50),即测试用例的数量。对于每个测试用例,第一行是两个整数N和M(1<=N,M<=1000)。N是小明所在班级的学生人数,M是结对人数。然后M线跟着。每行包含两个整数Ai和Bi,这意味着学生Ai和Bi在同一组中。
输出
对于每个测试用例,打印组中的学生人数,包括最少的学生。
输入样例1
2
5 3
1 2
2 3
4 5
6 5
2 3
1 4
4 5
5 3
2 6
输出样例 1
2
6

并查集,挺简单的,代码如下:

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int T;
int n,m;
const int M=1000+5;
int classc[M],cnt[M];
int minx;
int getf(int u)
{
	return classc[u]==u?u:classc[u]=getf(classc[u]);
}
void Merge(int v,int u)
{
	int t1=getf(v);
	int t2=getf(u);
	if(t1!=t2)classc[t2]=t1;
}
int main()
{
	cin>>T;
	while(T--)
	{
		minx=99999;
		memset(classc,-1,sizeof(classc));
		memset(cnt,0,sizeof(cnt));
		cin>>n>>m;
		int x,y;
		for(int i=1;i<=n;i++)
		{
			classc[i]=i;
		}
		//初始化 
		for(int i=1;i<=m;i++)
			{
				cin>>x>>y;
				Merge(x,y);
			}
		for(int i=1;i<=n;i++)
			cnt[getf(i)]++;
		for(int i=1;i<=n;i++)
			if(cnt[i]!=0)
				if(minx>cnt[i])
					minx=cnt[i];
		cout<<minx<<endl;
	}
	return 0;
}

Finding Friends
描述
Friendship is transitive. If A and B are friends and B and C are friends, then A and C are friends, and so on. Everyone can have many friends. Tom wants to know how many friends he has. Can you tell him?
输入
The first line is an integer T (T<50), the number of test cases. For each test case, its first line are two integer N and M (1<=N,M<=1000). N is the number of students in Xiao Ming’s class. M means the number of pairs. Then M lines followed. Each line contains two integers Ai and Bi, students Ai and Bi in the same group.
输出
For each test case, print the number of Tom’s friends. We asume that Tom is “1”.

并查集,只不过这次是输出1的组员,代码如下:

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int T;
int n,m;
const int M=1000+5;
int classc[M],cnt[M];
int minx;
int cn=0;
int getf(int u)
{
	return classc[u]==u?u:classc[u]=getf(classc[u]);
}
void Merge(int v,int u)
{
	int t1=getf(v);
	int t2=getf(u);
	if(t1!=t2)classc[t2]=t1;
}
int main()
{
	cin>>T;
	while(T--)
	{
		int sum=0;
		memset(classc,-1,sizeof(classc));
		memset(cnt,0,sizeof(cnt));
		cin>>n>>m;
		int x,y;
		for(int i=1;i<=n;i++)
		{
			classc[i]=i;
		}
		//初始化 
		for(int i=1;i<=m;i++)
			{
				cin>>x>>y;
				Merge(x,y);
			}
		for(int i=1;i<=n;i++)
			if(getf(i)==getf(1))
				sum++;
		cout<<sum-1<<endl;
	}
	return 0;
}

Doing Exercises
描述
As we all know, the line of students doing exercises between classes is always unsatisfactory to teachers. Today, a teacher wants to require something new. Firstly, he lets some students of N classes correspondingly form n lines. Then, he randomly selects a class to add some of its remaining students to its line, or selects a class to let some students leave its line, or lets the monitors from some adjacent classes report the total number of students in all these classes. This is very annoying for the monitors. Can you write a program to help them complete the reporting task?
输入
The first line is an integer T (T<50), the number of test cases. For each test case, its first line is an integer N (1<=N<=50000), representing the number of classes, and its second line include N integers (a1, a2, a3, … , an), and ai (1<=ai<=100) means the number of students in the line of class i at the beginning. Then, each next line will be an order. There are 4 kinds of orders:(1) “Add x i” means adding x students to the line of class i.(2) “Sub x i” means that x students leave the line of class i.(3) “Query i j” means that the monitors from class i to class j report the teacher the total number (sum) of students in their classes at that moment (i<j).(4) “End” means ending the exercises, which will only appear at the end of each test case.The number of orders will not exceed 40000. The number of students in any line will never below 0.
输出
For each test case, you must print “Case i:” in the first line. Then for each Query, print the result in one line.

做运动
描述
众所周知,学生在课间做练习的路线总是让老师不满意。今天,老师想要求一些新的东西。首先,他让N个班级的一些学生相应地组成N条线。然后,他随机选择一个类,将其剩余的一些学生添加到其行中,或者选择一个类,让一些学生离开其行,或者让相邻类的监控器报告所有这些类中的学生总数。这对监视器来说很烦人。你能写一个程序来帮助他们完成报告任务吗?
输入
第一行是一个整数T(T<50),即测试用例的数量。对于每个测试用例,它的第一行是一个整数N(1<=N<=50000),表示类的数量,第二行包括N个整数(a1,a2,a3,an),ai(1<=ai<=100)是指一班一行开始时的学生人数。然后,下一行将是一个订单。有4种命令:(1)“Add x i”表示在一班的行中添加x个学生。(2)“Sub x i”表示x个学生离开一班的行。(3)“Query i j”表示从一班到j班的班长向老师报告当时所在班的学生总数(总和)(i<j)。(4)“End”表示结束练习,它只出现在每个测试用例的末尾。订单数量不会超过40000。任何一行的学生数量都不会低于0。
输出
对于每个测试用例,必须在第一行打印“casei:”。然后,对于每个查询,将结果打印在一行中。
==输入样例 1 ==
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 2 10
Add 3 6
Query 3 10
End
输出样例 1
Case 1:
6
30
56

线段树,每个存的值是和,代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=50000;
int T;
struct Node
{
	int l,r;
	int sum;
	int len;//区间长度 
	int lazy;
};
Node tree[4*N];
int a[N],cnt=0;
void build(int root,int L,int R)
{
	tree[root].l=L;
	tree[root].r=R;
	tree[root].len=R-L+1;
	tree[root].lazy=0;
	if(L==R)
	{
		tree[root].sum=a[L];
		return ;
	 } 
	 int mid=(tree[root].l+tree[root].r)/2;
	 build(2*root,L,mid);
	 build(2*root+1,mid+1,R);
	 tree[root].sum=tree[2*root].sum+tree[2*root+1].sum;
}
void pushdown(int root)
{
	if(tree[root].lazy)
	{
		tree[root*2].lazy+=tree[root].lazy;
		tree[2*root+1].lazy+=tree[root].lazy;
		tree[root*2].sum+=tree[root*2].len*tree[root].lazy;
		tree[2*root+1].sum+=tree[root*2+1].len*tree[root].lazy;
		tree[root].lazy=0;
	}
}
void update(int root,int l,int r,int c)//s,e,c
{
	if(tree[root].l>=l&&tree[root].r<=r)
	{
		tree[root].sum+=c*tree[root].len;
		tree[root].lazy+=c;
		return ;
	}
	if(tree[root].l>r||tree[root].r<l)
		return ;
	if(tree[root].lazy)
		pushdown(root);
	update(2*root,l,r,c);
	update(2*root+1,l,r,c);
	tree[root].sum=tree[root*2].sum+tree[root*2+1].sum;
}
int query(int root ,int l,int r)
{
	if(tree[root].l>=l&&tree[root].r<=r)
		return tree[root].sum;
	if(tree[root].l>r||tree[root].r<l)
		 return 0;
	if(tree[root].lazy)
		pushdown(root);
	return query(2*root,l,r)+query(2*root+1,l,r);
}
void updata(int root,int i,int v)
{
	if(tree[root].l==i&&tree[root].r==i)
    {
        tree[root].sum+=v;
        return ;
    }
    int mid=(tree[root].l+tree[root].r)/2;
    if(i<=mid)
        updata(2*root,i,v);
    else
        updata(2*root+1,i,v);
    tree[root].sum=tree[2*root].sum+tree[2*root+1].sum;    //回溯获得左右孩子最大值
}
int main()
{
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		cnt+=1;
		cout<<"Case "<<cnt<<":"<<endl;
		build(1,1,n);
		string s;
		string s1="End",s2="Add",s3="Query",s4="Sub";
		while(cin>>s)
		{
			int x,y;
			if(s==s1)
				break;
			else if(s==s2)//add
			{
				cin>>x>>y;
				updata(1,y,x);
			}
			else if(s==s4)//sub
			{
				cin>>x>>y;
				updata(1,y,-x);
			}
			else if(s==s3)//que
				{
					cin>>x>>y;
					cout<<query(1,x,y)<<endl;
				}
		}
	}
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值