PTA天梯模拟补题

文章包含多个C++实现的算法问题,如正整数加法、租车、判断素数、红色警报(DFS计算连通分支)、列车调度、有情人关系判断、完全二叉搜索树验证以及Dijkstra最短路径。每个问题都展示了不同的数据结构(如set、map)和搜索策略(如DFS、队列思想)。
摘要由CSDN通过智能技术生成

目录

7-1 正整数A+B (15)

7-3 出租(20)set + map

7-4 判断素数(10)

7-9 红色警报(25)DFS计算连通分支

7-10 列车调度(25)queue思想 + set

7-12 愿天下有情人都是失散多年的兄妹(25)DFS

7-13 是否完全二叉搜索树(30)二叉搜索树 + 完全二叉树层序遍历

7-14 直捣黄龙(30)Dijkstra(路径+各种数组)+ unordered_map

7-15 水果忍者(30)几何


7-1 正整数A+B (15)

A和B中间可能会有大于一个空格,除第一个空格外的空格属于B,cin俩个string字符串不可行

也可使用stio函数进行优化将字符串直接转化成数字,还要手动判断两数的范围

#include<bits/stdc++.h>
using namespace std;
int n;
string a,b;
int x=0,y=0;
int chang(string s){
	int t=0;
	for(int i=0;s[i]!='\0';i++){
		if(s[i]<='9'&&s[i]>='0')t*=10,t+=s[i]-'0';
		else return -1;
	}if(t>=1&&t<=1000)return t;
	else return -1;
}
int main(){
	cin >> a;
	getchar();
	getline(cin, b);
	//cin>>a>>b;
	//cout<<a<<' '<<b<<endl;
	x=chang(a),y=chang(b);
	if(x>0&&y>0) printf("%d + %d = %d",x,y,x+y);
	else if(x>0) printf("%d + ? = ?",x);
	else if(y>0) printf("? + %d = ?",y);
	else printf("? + ? = ?");
	return 0;
}

7-3 出租(20)set + map

0需要进行特判 利用set去重得到数组arr[ ],需注意a.rbegin()反向迭代器与正向迭代器不可混用,erase元素时直接*rbegin()删除元素本身 

#include<bits/stdc++.h>
using namespace std;
long long n,n1;
string x,y;
set<int>a;
map<int,int>m;
int main(){
	cin>>x;
	for(int i=0;i<11;i++)n=n*10+x[i]-'0';
	n1=n;
	if(n==0)a.insert(0);
	while(n) a.insert(n%10),n/=10;
	printf("int[] arr = new int[]{");
	int len=a.size();
	for(int i=len,j=0;i>=1;i--,j++){
		int t=*a.rbegin();
		printf("%d",t);
		if(i!=1)printf(",");
		a.erase(*a.rbegin());
		m[t]=j;
	}
	
	printf("};\nint[] index = new int[]{");
	for(int i=0;i<11;i++){
		printf("%d",m[x[i]-'0']);
		if(i!=10)printf(",");
		else printf("};");
	}
}

7-4 判断素数(10)

1不是素数需要特判  

#include<bits/stdc++.h>
using namespace std;
int n;
long long x;
int f;
void prime(long long x){
		long long y=sqrt(x);
		for(int i=2;i<=y;i++){
			if(x%i==0){
				f=0;
				return;
			}
		}	
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&x);
		 f=1;
		prime(x);
        if(x==1)printf("No\n");
        else if(f)printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

7-9 红色警报(25)DFS计算连通分支

 dfs深度优先遍历判断有几个连通分支,增加f[ ]记录是否被攻占 

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
const int N = 550;
//const double INF = 1e18;
int n,m,k,x,y;
int sum,sumt;
int f[N];//被攻占 
int vis[N];//被访问 
vector<int>edge[N];
void dfs(int x){
	for(auto i:edge[x]){
		if(!f[i]&&!vis[i]){//未被攻占且未被访问 
			vis[i]=1;
			dfs(i);
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		edge[x].push_back(y);
		edge[y].push_back(x);
	}
	for(int i=0;i<n;i++){
		if(!vis[i]){
			dfs(i);sum++;
			//printf("i:%d sum:%d\n",i,sum);
		}
	}//printf("%d\n",sum);
	scanf("%d",&k);
	int cnt=n;
	for(int i=1;i<=k;i++){
		scanf("%d",&x);
		f[x]=1;sumt=0;cnt--;
		memset(vis,0,sizeof(vis));
		for(int j=0;j<n;j++){
			if(!vis[j]&&!f[j]){
				dfs(j);sumt++;
				//printf("j:%d sumt:%d\n",j,sumt);
			}
		}
		if(sumt<=sum)printf("City %d is lost.\n",x);
		else printf("Red Alert: City %d is lost!\n",x);
		sum=sumt;
		if(!cnt)printf("Game Over.");
	}
	return 0;
}

7-10 列车调度(25)queue思想 + set

认真读题,输入的已经是反向序列,直接入队即可

利用set实现自动排序

b.upper_bound(m)大于m的最小数 

#include<bits/stdc++.h>
using namespace std;
int n,m;
set<int>b;
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++){
		scanf("%d", &m);
		if (b.upper_bound(m) != b.end()) {
			b.erase(b.upper_bound(m));
		}b.insert(m);
    }printf("%d", b.size());
	return 0;
}

7-12 愿天下有情人都是失散多年的兄妹(25)DFS

DFS递归追溯上五代出现过的人,标记是否出现过,记录深度d

有两条线需向上追溯时不能直接return

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6;
char a[N];
int node[N][2];
int n, id, sex, f, m;
bool flag;
int vis[N];
void solve(int x,int d) {
	//printf("d:%d vis[%d]:%d f:%d m:%d\n",d, x, vis[x],node[x][0],node[x][1]);
	if (vis[x])flag=0;
	vis[x] = 1;
	if (d == 5)return;
	if (node[x][0] != -1) solve(node[x][0], d + 1);
	if (node[x][1] != -1) solve(node[x][1], d + 1);
}
int main() {
	memset(node, -1, sizeof(node));
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &id);
		scanf("%s%d%d", &a[id], &f, &m);
		a[f] = 'M', a[m] = 'F';
		node[id][0] = f, node[id][1] = m;
	}
	int k, x, y; scanf("%d", &k);
	for (int i = 1; i <= k; i++) {
		scanf("%d%d", &x, &y);
		if (a[x] == a[y])printf("Never Mind\n");
		else {
			memset(vis, 0, sizeof(vis));
			flag = 1;
			solve(x, 1); solve(y, 1);
			if (flag)printf("Yes\n");
			else printf("No\n");
		}
	}
	return 0;
}

7-13 是否完全二叉搜索树(30)二叉搜索树 + 完全二叉树层序遍历

 根据题目要求建立一颗二叉搜索树(左大右小),后层序遍历判断是否是完全二叉树(出现一个空节点后的所有节点需为空) 

#include<bits/stdc++.h>
using namespace std;
int n,a[100],x;
void add(int x,int id){
	if(!a[id])a[id]=x;
	else if(a[id]<x)add(x,id*2);
	else add(x,id*2+1);
	return;
}
int main() {
	memset(a,0,sizeof(a));
	scanf("%d", &n);
	for (int i = 1; i <= n; i++){
		scanf("%d", &x);
		add(x,1);
    }queue<int>q;
    q.push(1);
    int f=1,ani=0;
    while(!q.empty()){
    	int i=q.front(),t=a[i];q.pop();
		if(a[i*2]){
			if(ani)f=0;
			q.push(i*2);
		}else ani=1;
		
		if(a[i*2+1]){
			if(ani)f=0;
			q.push(i*2+1);
		}else ani=1;
		printf("%d",t);
		if(!q.empty())printf(" ");
	}if(f)printf("\nYES");
	else printf("\nNO");
	return 0;
}

7-14 直捣黄龙(30)Dijkstra(路径+各种数组)+ unordered_map

单源无负边权->Dijsktra最短路

num[ ];//最短路条数
p[ ];//记录路径
sumv[ ];//打败敌军数量 
numcity[ ];//救援城市数目

根据 最快速度(最短路径)->沿途解放最多城镇(numcity[ ])->有效杀伤最多敌军(sumv[ ])的次序判断并不断更新各个数组

unordered_map映射string->int及int->string

//最快速度->沿途解放最多城镇->有效杀伤最多敌军
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
const int N = 205;
const double INF = 1e18;
int n,m,z,v[N],dist[N*4];//v[]敌军数 
struct node{
	int y,v;
	node(int _y,int _v){y=_y,v=_v;}
};
vector<node>edge[N];
set<pair<int,int>>q;
unordered_map<string,int>mp;//字符对应序号
unordered_map<int,string>mp2;//序号到字符串 
int num[N];//最短路条数
int p[N];//记录路径
int sumv[N];//打败敌军数量 
int numcity[N];//救援城市数目
 

void Dijsktra(int s,int t){
	memset(dist,127,sizeof(dist));
	dist[s]=0;q.clear();num[s]=1;
	for(int i=1;i<=n;i++)
		q.insert(make_pair(dist[i],i)); 
	while(!q.empty()){
		int x=q.begin()->second;
		q.erase(q.begin());
		if(dist[x]>1<<30||x==t)break;
		for(auto i:edge[x]){
			if(dist[i.y]>dist[x]+i.v){
				q.erase(make_pair(dist[i.y],i.y));
				dist[i.y]=dist[x]+i.v;
				q.insert(make_pair(dist[i.y],i.y));
				numcity[i.y]=numcity[x]+1;
				sumv[i.y]=sumv[x]+v[i.y];
				p[i.y]=x;
				num[i.y]=num[x];
			}else if(dist[i.y]==dist[x]+i.v){
				//if(dist[t]==mins)num++;
				//else num=1,mins=dist[t];
				num[i.y]+=num[x];
				
				if(numcity[i.y]<numcity[x]+1){
					numcity[i.y]=numcity[x]+1;
					sumv[i.y]=sumv[x]+v[i.y];
					p[i.y]=x;
				}
				else if(numcity[i.y]==numcity[x]+1){
					if(sumv[i.y]<sumv[x]+v[i.y]){
						sumv[i.y]=sumv[x]+v[i.y];
						p[i.y]=x;
					}
				}
			}
		}
	}
}
void findp(int x){
	if(x!=1)findp(p[x]);
	cout<<mp2[x]<<"->";
}
int main(){
	scanf("%d%d",&n,&m);
	string ss1,ss2,x,y;
	cin>>x>>y;
	mp[x]=1;mp2[1]=x;
	for(int i=2;i<=n;i++){
		cin>>ss1>>v[i];
		mp[ss1]=i;mp2[i]=ss1;
	}for(int i=1;i<=m;i++){
		cin>>ss1>>ss2>>z;
		edge[mp[ss1]].push_back(node(mp[ss2],z));
		edge[mp[ss2]].push_back(node(mp[ss1],z));
	}Dijsktra(mp[x],mp[y]);
	findp(p[mp[y]]);
	cout<<y<<endl;
	printf("%d %d %d",num[mp[y]],dist[mp[y]],sumv[mp[y]]);
	return 0;
}

 7-14 直捣黄龙 (30 分)(djkstra,map,dfs)_forget……的博客-CSDN博客

7-15 水果忍者(30)几何

 枚举每一条线段的下端点,从这个下端点向别的线段的上端点和下端点连线,然后判断一下(所有线段的上端点的最小斜率) 是不是大于 (所有线段的下端点的最小斜率),如果有合法的,那么所有线段的上端点的最小斜率对应的那个点和所有线段的下端点的最小斜率对应的点都是合法的,输出此时作为标准的点的下端点,另外一个点从两个合法的情况中找一个就可以了。

ps:假设当前枚举的是第i条线段,当我们枚举第i-1条线段的时候,形成的斜率可能会出现负数的情况。这个时候就相当于原来的上面的斜率变成了下面的斜率,下面的斜率变成了上面的斜率,注意坐标也要做相应的变化。

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define inf 0x3f3f3f3f
const int maxn = 2e4 + 100;
struct node {
	int x, y1,y2;
}q[maxn];
int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d%d%d", &q[i].x, &q[i].y1, &q[i].y2);
	}
	for (int i = 1; i <= n; i++) {
		double minn = inf, maxx = -inf;
		int  xup, yup;
		//xup=yup=0;
		int j;
		for (j = 1; j <= n; j++) {
			if (j == i)continue;
			int flag = 1;
			double up = (q[j].y1 * 1.0 - q[i].y2 * 1.0) / (q[j].x * 1.0 - q[i].x * 1.0);
			double down = (q[j].y2 * 1.0 - q[i].y2 * 1.0) / (q[j].x * 1.0 - q[i].x * 1.0);
			if (up < down)swap(up, down), flag = 0;
			if (down > minn || up < maxx)break;
			//所有线段的上端点的最小斜率对应的那个点和所有线段的下端点的最小斜率对应的点都是合法的
			//输出此时作为标准的点的下端点,另外一个点从两个合法的情况中找一个,此处取上端点
			maxx = max(maxx, down);
			if (minn > up) {
				minn = up;
				xup = q[j].x;
				yup = q[j].y1;
				if (!flag) yup = q[j].y2;
			}
		}
		if (j == n + 1) {
			printf("%d %d %d %d\n", q[i].x, q[i].y2, xup, yup);
			break;
		}
	}
	return 0;
}

7-15 水果忍者 (30 分) - Let_Life_Stop - 博客园 (cnblogs.com)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值