东北农业大学2020寒假acm培训day3数据结构基础

东北农业大学2020寒假acm培训day3数据结构基础

第一次写,也别指望我写好多,并且能力有限,很多题想复杂了,求大佬轻骂

题目传送门 点我点我

PROBLEM A 消消乐

为了简化问题,现在只在一行上进行消消乐,而且只要相邻元素相同就可以消掉。
现在给出一个行消消乐的序列,问可以消除多少次?

思路:每2个相邻一样的便需要消除,可以从第一个开始一个一个判断邻位是否相等,但假如拿数组存的话,每次删除后需要把后面所有数字往前移动2位,时间复杂度太大,所以建议直接使用栈做,从第一位开始放入栈,假如栈空,直接放入,栈非空时,判断栈顶元素与代插入元素是否相等,相等时栈顶元素直接退栈,不相等时进栈

重点

假如你的栈和我一样是全局变量,每次跑完一组数据的时候,一定一定一定要清空栈

代码:

#include <bits/stdc++.h>
#include <stack>
#include <string>
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T,i;
	string s1;
	stack <int> qwe;
	cin>>T;
	while(T--) {
		int num=0;
		cin>>s1;
		int n=s1.size();
		for(i=0; i<n; i++) {
			if(qwe.empty() || qwe.top()!=s1[i])
				qwe.push(s1[i]);
			else {
				num++;
				qwe.pop();
			}
		}
		cout<<num<<"\n";
		while(!qwe.empty())
			qwe.pop();
	}
	return 0;
}

PROBLEM B 队列操作

数据结构基础之一——队列
队列有五种基本操作,插入队尾、取出队首、删除队首、队列大小、清空队列
思路: 没啥好说的,就是个简单模拟,甚至都不用你自己写各种函数原型,直接用queue的头文件就可以了,细心点就行,同样的,全局变量的队列,记得清空(有一说一,我似乎写麻烦了)
代码:

#include <bits/stdc++.h>
#include <queue>
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T,n,q;
	cin>>T;
	string s1;
	queue <int> a;
	while(T--) {
		cin>>n;
		while(n--) {
			cin>>s1;
			switch(s1[0]) {
				case'P': {
					if(s1[1]=='O') {
						if(a.empty())
							cout<<-1<<"\n";
						else
							a.pop();
					} else {
						cin>>q;
						a.push(q);
					}
					break;
				}
				case'T': {
					if(a.empty())
						cout<<-1<<"\n";
					else
						cout<<a.front()<<"\n";
					break;
				}
				case'S': {
					cout<<a.size()<<"\n";
					break;
				}
				case'C': {
					while(!a.empty())
						a.pop();
					break;
				}
			}
		}
		while(!a.empty())
			a.pop();
	}
	return 0;
}

PROBLEM C 树的深度

给你一个含有n个结点的树,然后有Q次询问,每一次询问,问你这个结点的深度是多少
思路: 问某个结点的深度,其实就是他的父亲结点可以推到哪,
假如他前面没有父亲节点,那他就是根节点,深度为1,他有父亲,但他父亲没有父亲了,那他度就是2,以此类推,所以可以直接通过循环,得出他一直到根节点,经历了几任爸爸
代码:(我代码写复杂了,直接copy罗学姐的了,看不懂的去问他)

#include<bits/stdc++.h>
using namespace std;
int fa[100005];
int main() {
	int n;
	int t;
	cin>>t;
	while(t--) {
		scanf("%d",&n);
		for(int i=1; i<=n; i++)
			scanf("%d",&fa[i]);
		int q;
		scanf("%d",&q);
		while(q--) {
			int x;
			scanf("%d",&x);
			int ans=0;
			while(x) {
				x=fa[x];
				ans++;
			}
			cout<<ans<<endl;
		}
	}
	return 0;
}

PROBLEM D 最近距离

给出一个有向图,请找出从s到e的最小距离并且必须仅经过中间某点k
思路: 全场最最最水的一题了,但是就2个人过,因为题意太模糊了,把题意说一下就行,s到e,经过且经过一点,所以拿样例举例,
1到1,除非是1->2,2->3,3->4,4->5,5->1,经过了不止一个点,所以输出-1,
1到2,要么不经过其他任何点,要么得像之前那样跑一个循环,也不行,
1到3,1->2,2->3,刚好只经过2,成立,
1到3,1->2,2->3,3->4,经过了2和3一共两个点,不成立
所以本题其实跑一个循环就够了,看代码
代码:

#include <bits/stdc++.h>
using namespace std;
int num[1500][1500];
int main()
{
	int T,x,y,z,i,j,n,m,q;
	//cin>>T;
	//while(T--)
	{
		memset(num,0,sizeof(num));
		cin>>n>>m>>q;
		//for(i=1;i<=n;i++)
		
			for(j=1;j<=m;j++)
			{
				cin>>x>>y>>z;
				num[x][y]=z;
			}
		while(q--)
		{
			int minn=10000000;
			cin>>x>>y;
			for(i=1;i<=n;i++)
			{
				if(num[x][i] && num[i][y] && (i!=x)&& (i!=y))
				{
					minn=min(minn,num[i][y]+num[x][i]);
				}
			}
			if(minn!=10000000)
			cout<<minn<<"\n";
			else
			cout<<-1<<"\n";
		}
	}
	return 0;
}

PROBLEM E 子结点

给你一个含有n个结点的树(结点编号为1~n),然后有Q次询问,每一次询问,问你这个结点的所有子结点编号。
思路: 有一说一,C题跟这题异曲同工之妙,C题找父亲,这题一样找父亲就完事了,并且只要找一次,找到父亲结点后,创立一个vector容器,在对应的父亲结点里,放入自己的编号就行(我一开始看错题了,以为是子孙结点,把祖先找光了,代码有点麻烦了,但改一下就能当子孙结点了,感兴趣的话可以自己试下)
代码:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
P a[100005];
int num[100005];
vector<int>vbn[100005];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T,n,i,q,x;
	cin>>T;
	while(T--) {
		memset(num,0,sizeof(num));
		memset(a,0,sizeof(a));

		cin>>n>>q;
		for(i=1; i<=n; i++) {
			vbn[i].clear();
		}
		for(i=1; i<=n; i++) {
			cin>>x;
			a[i].first=x;
			a[i].second=i;
			x=i;
			if(a[x].first) {

				num[a[x].first]++;
				x=a[x].first;
				vbn[x].push_back(i);
			}//把这里的if改成where,就可以求出所有的子孙结点了 
		}
		while(q--) {
			cin>>x;
			cout<<num[x];
			for(i=0; i<num[x]; i++) {
				cout<<" "<<vbn[x][i];
			}
			cout<<"\n";
		}
	}
	return 0;
}

PROBLEM F 第k层祖先

给你一个满二叉树,有Q次询问,每一次询问让你找一个编号为x的结点在深度为k的祖先节点的编号是多少?
思路: 无fuck可说,不懂满二叉树的话可以点这里点我,懂吗?你把定义看看,这题就会了,我直接贴代码了
代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int T;
	long long x,k,q;
	cin>>T;
	while(T--)
	{
		cin>>x>>k;
		q=pow(2,k);//强烈建议换成下面的,我自己偷懒这么写的
		//q=1LL<<x 
		if(x<q)
		cout<<-1<<"\n";
		else
		{
			while(x>=q)
			x/=2;
			cout<<x<<"\n";
		}
	}
	return 0;
}

PROBLEM G 子节点问题2

给你n个节点,告诉你每一个节点下面的子节点的数量,问你是否可以构成一颗树
思路: (无fuck说)^2,百度定义去,n个结点的树的边有且仅有n-1条边,你算下总值是不是n-1就行
重点: 空树也是树,空树也是树,空树也是树,空树也是树,
空树也是树,空树也是树,空树也是树
代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	long long int n,i,a,sum;
	cin>>n;
	sum=0;
	for(i=1;i<=n;i++)
	{
		cin>>a;
		sum+=a;
	}
	if(n==0)
	cout<<"YES\n";
	else
	if(sum==n-1)
	{
		cout<<"YES\n";
	}
	else
	cout<<"NO\n";
	return 0;
}

PROBLEM H ++的院子

++的院子里有一种很奇怪的结构,上面有4个结点,n条边。他想知道这种结构是不是树。
**思路:**开门见山,我的思路,绝对不是最优解,我的思路首先判断,边是不是3个,因为一共4个点,必须是4-1条边才能构成树,
或者假如出现了自己连自己,也可以直接排除
确定3条边后,我们可以很轻易的举出很多种情况,那么我们反向思维,什么时候不成立
在这里插入图片描述
所以我通过邻接矩阵存的边的关系,判断是否存在某2个点重复连了2次边,或者某个点从始至终没跟其他点连接过,如果成立,就不是树
具体见代码实现
代码:

#include <bits/stdc++.h>
using namespace std;
int qwe[5][5];
int sum[5];
int main()
{
	int T,n,flag=1,i,j,x,y;
	cin>>T;
	while(T--)
	{
		memset(qwe,0,sizeof(qwe));
		memset(sum,0,sizeof(sum));
		flag=1;
		cin>>n;
		for(i=0;i<n;i++)
		{
			cin>>x>>y;
			if(x==y)//自环直接死 
			flag=0;
			qwe[x][y]++;
			qwe[y][x]++;
		}
		if(n==3)
		{
			for(i=1;i<=4;i++)
			{
				for(j=1;j<=4;j++)
				{
					if(qwe[i][j]>=2)//同一边出现2次 
					{
						flag=0;
						break;
					}
				}
				if(!flag)
				break;
			}
			for(j=1;j<=4;j++)
			{
				int asd=0;
				for(i=1;i<=4;i++)
				{
					if(qwe[i][j])
					asd++;
				}
				sum[j]=asd;
				if(sum[j]==0)//假如某个点没有跟任何点相连,也不是树 
				{
					flag=0;
					break;
				}
			}
		}
		else
		flag=0;
		if(flag)
		cout<<"++\n";
		else
		cout<<"--\n";
	}
	return 0;
}

PROBLEM I Stick

现在有n个木棒,每一个木棒都有一个长度,现在想让你将这n个木棒合并成为一个长的木棒,已知合并的时候每一次只能选择任意两根木棒进行合并,合并的代价为这两个木棒的长度,现在让你求所有可能方案中合并的代价总和最小为多少?
思路: oj上的原题,你要是不会就代表你没好好补题了,(然后数据上看今天之前似乎就我写过。。。。并且那套题我刚好只写了这一题,很巧合)传送门来了点我,亲
并且 poj上也有一道同样的题,你同样可以试试,给你个传送门我就是,点我就行了
优先队列模板题,你要是用霍夫曼树做的话poj上是不会超时的,(咱们学校oj我没试,逃)
代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int T,i;
	cin>>T;
	while(T--)
	{
		ll n=0,x=0,ans=0;
		priority_queue<ll,vector<ll>,greater<ll> >q;
		cin>>n;
		for(i=1;i<=n;i++)
		{
			cin>>x;
			q.push(x);
		}
		while(q.size()>=2)
		{
			ll a=q.top();q.pop();
			ll b=q.top();q.pop();
			ans+=a+b;
			q.push(a+b);
		}
		cout<<ans<<"\n";
	}
	return 0;
}

PROBLEM J 字符价值

我代码突然tle了,以及我累了,逃,等我改下再来

发布了2 篇原创文章 · 获赞 8 · 访问量 337

猜你喜欢

转载自blog.csdn.net/WWL0702/article/details/103931909