数据结构与算法训练:第十八弹

1. 知识点总结

98/100耗时2h,最后一题还剩2分没有继续死磕了……哇啊。

题目难度知识点
1108 Finding Average🎯字符串处理
1109 Group Photo🎯STL排序+数组下标处理
1110 Complete Binary Tree🎯完全二叉树判断
1111 Online Map🎯🎯|✨最短路径+DFS

2. 分题题解

2.1 1108 Finding Average

还记得以前第一次见到这种题目的时候,觉得很麻烦,特别是对于字符串合法性判断的地方,写多了其实还是有点手感的,代码比以前减少冗余了捏~

#include<bits/stdc++.h>
using namespace std;
int N,cnt=0;
double num,sum=0;
string str;
bool isLegal(string str,double &num){
	int len=str.length();
	//首先判断是否是数字
	int dot_pos=-1;
	for(int i=0;i<len;i++){
		if((str[i]=='+'||str[i]=='-')&&i==0){
			continue;
		}else if(str[i]<='9'&&str[i]>='0'){
			continue;
		}else if(str[i]=='.'&&dot_pos==-1){
			dot_pos=i;
			continue;
		}else{
			return false;
		}
	} 
	if(dot_pos!=-1&&len-dot_pos-1>=3){
		return false;
	}
	num=atof(str.c_str());
	if(num<-1000||num>1000){
		return false;
	}
	return true;
}
int main(){
	scanf("%d",&N);
	getchar();
	for(int i=0;i<N;i++){
		cin>>str;
		if(isLegal(str,num)){
			sum+=num;
			cnt++;
		}else{
			printf("ERROR: %s is not a legal number\n",str.c_str());
		}
	}
	if(cnt==0){
		printf("The average of %d numbers is Undefined",cnt);
	}else if(cnt==1){
		printf("The average of %d number is %.2f",cnt,sum/cnt);
	}else{
		printf("The average of %d numbers is %.2f",cnt,sum/cnt);
	}
	return 0;
} 

2.2 1109 Group Photo

好像也是之前卡住的题目,主要在行排序的规则的理解,因为数组开的是[0,m-1]所以第一个位置下标号应该是m/2,然后左右散开排列

#include<bits/stdc++.h>
using namespace std;
struct Node{
	string name;
	int height;
};
int N,K,m;
vector<Node>nodes,row;
bool cmp(Node a,Node b){
	if(a.height!=b.height){
		return a.height>b.height;
	}else{
		return a.name<b.name;
	}
}
int main(){
	scanf("%d%d",&N,&K);
	nodes.resize(N);
	for(int i=0;i<N;i++){
		cin>>nodes[i].name>>nodes[i].height;
	}
	sort(nodes.begin(),nodes.end(),cmp);
	int index=0;
	for(int i=0;i<K;i++){
		if(i==0){
			m=N/K+N%K;
		}else{
			m=N/K;
		}
		row.resize(m);
		//下面开始排列位置
		int pos=m/2;
		int posl=pos-1;
		int posr=pos+1;
		row[pos]=nodes[index++];
		for(int x=0;x<m-1;x++){
			//printf("pos=%d,posl=%d,posr=%d\n",pos,posl,posr);
			if(x%2==0){
				row[posl]=nodes[index++];
				posl--;
			}else{
				row[posr]=nodes[index++];
				posr++;
			}
		}
		//输出本行结果
		for(int x=0;x<m;x++){
			if(x){
				printf(" ");
			}
			printf("%s",row[x].name.c_str());
		} 
		printf("\n");
	}
	return 0;
}

2.3 1110 Complete Binary Tree

基于数组的完全二叉树的判断,需要背住的模板。

#include<bits/stdc++.h>
using namespace std;
struct Node{
	int val;
	int left=-1;
	int right=-1;
};
int N,ans;
vector<Node>nodes;
vector<bool>isC;
string a,b;
//判断是否是完全二叉树
bool isComplete(int root){
	queue<int>q;
	q.push(root);
	while(!q.empty()){
		int top=q.front();
		q.pop();
		if(top==-1){
			break;
		}else{
			ans=top;
		}
		q.push(nodes[top].left);
		q.push(nodes[top].right);
	}
	while(!q.empty()){
		int top=q.front();
		if(top!=-1){
			return false;
		}
		q.pop();
	}
	return true;
} 
int main(){
	scanf("%d",&N);
	nodes.resize(N);
	isC.resize(N);
	fill(isC.begin(),isC.end(),false);
	for(int i=0;i<N;i++){
		nodes[i].val=i;
		cin>>a>>b;
		if(a!="-"){
			nodes[i].left=atoi(a.c_str());
			isC[atoi(a.c_str())]=true;
		}
		if(b!="-"){
			nodes[i].right=atoi(b.c_str());
			isC[atoi(b.c_str())]=true;
		}
	}
	int root;
	for(int i=0;i<N;i++){
		if(!isC[i]){
			root=i;
			break;
		}
	}
	if(isComplete(root)){
		printf("YES %d",ans);
	}else{
		printf("NO %d",root);
	}
	return 0;
}

2.4 1111 Online Map

最短路径+DFS

求两条路径,一条是最短距离路径(距离相等时取耗时最短),一条是最短时间路径(时间相等时取经过节点最少)

emm没有订正,下面的代码错了测试点2被扣2分~看了柳神的代码,贴在后面参考资料——真的简练😍

#include<bits/stdc++.h>
using namespace std;
//最短、最快 
const int inf=INT_MAX;
int N,M;
vector<vector<int> >t,d;//时间,距离
int u,v,one_way,len,tim,st,ed; 
//对于最短路径,如果相同,选择其中最快的
vector<vector<int> >pre;
vector<int>temp,short_path,fast_path;
int min_time=inf,min_i=inf;
void DFS_f(int id,vector<int>temp){
	temp.push_back(id);
	if(id==st){
		//计算时间 
		int temp_time=0;
		for(int i=temp.size()-1;i>=1;i--){
			temp_time+=t[temp[i]][temp[i-1]];
		}
		if(temp_time<min_time){
			min_time=temp_time;
			short_path=temp;
		}
	}else{
		for(int i=0;i<pre[id].size();i++){
			DFS_f(pre[id][i],temp);
		}
	}
	temp.pop_back();
}
void DFS_i(int id,vector<int>temp){
	temp.push_back(id);
	if(id==st){
		int cnt=temp.size();
		if(cnt<min_i){
			min_i=cnt;
			fast_path=temp;
		}
	}else{
		for(int i=0;i<pre[id].size();i++){
			DFS_i(pre[id][i],temp);
		}
	}
	temp.pop_back();
}
int findShortest(int st,int ed){
	pre.resize(N);
	vector<int>dis(N);
	vector<bool>vis(N,false);
	fill(dis.begin(),dis.end(),inf);
	dis[st]=0;
	while(1){
		int u=-1;
		int min_dis=inf;
		for(int i=0;i<N;i++){
			if(!vis[i]&&dis[i]<min_dis){
				min_dis=dis[i];
				u=i;
				break;
			}
		}
		if(u==-1){
			break;
		}
		vis[u]=true;
		//更新路径
		for(int v=0;v<N;v++){
			if(dis[u]==inf){
				break;
			}
			if(d[u][v]==inf){
				continue;
			}else if(dis[v]>dis[u]+d[u][v]){
				pre[v].clear();
				pre[v].push_back(u);
				dis[v]=dis[u]+d[u][v];
			}else if(dis[v]==dis[u]+d[u][v]){
				pre[v].push_back(u);
				dis[v]=dis[u]+d[u][v];
			}
		} 
	}
	//寻找最短且最快的路径
	DFS_f(ed,temp);
	return dis[ed];
}
//对于最快路径,选择其中size最小的
int findFast(int st,int ed){
	pre.clear();
	pre.resize(N);
	vector<int>dis(N);
	vector<bool>vis(N,false);
	fill(dis.begin(),dis.end(),inf);
	dis[st]=0;
	while(1){
		int u=-1;
		int min_dis=inf;
		for(int i=0;i<N;i++){
			if(!vis[i]&&dis[i]<min_dis){
				min_dis=dis[i];
				u=i;
				break;
			}
		}
		if(u==-1){
			break;
		}
		vis[u]=true;
		//更新路径
		for(int v=0;v<N;v++){
			if(dis[u]==inf){
				break;
			}
			if(t[u][v]==inf){
				continue;
			}else if(dis[v]>dis[u]+t[u][v]){
				pre[v].clear();
				pre[v].push_back(u);
				dis[v]=dis[u]+t[u][v];
			}else if(dis[v]==dis[u]+t[u][v]){
				pre[v].push_back(u);
				dis[v]=dis[u]+t[u][v];
			}
		} 
	}
	temp.clear();
	DFS_i(ed,temp);
	return dis[ed];
}
int main(){
	scanf("%d%d",&N,&M);
	t.resize(N);
	d.resize(N);
	for(int i=0;i<N;i++){
		t[i].resize(N);
		fill(t[i].begin(),t[i].end(),inf);
		d[i].resize(N);
		fill(d[i].begin(),d[i].end(),inf);
	}
	for(int i=0;i<M;i++){
		scanf("%d%d%d%d%d",&u,&v,&one_way,&len,&tim);
		t[u][v]=tim;
		d[u][v]=len;
		if(one_way==0){
			t[v][u]=tim;	
			d[v][u]=len;
		}
	}
	scanf("%d%d",&st,&ed);
	int ans1=findShortest(st,ed);
	int ans2=findFast(st,ed);
	if(short_path==fast_path){
		printf("Distance = %d; Time = %d:",ans1,ans2);
		int len1=short_path.size();
		for(int i=len1-1;i>=0;i--){
			if(i!=len1-1){
				printf("->");
			}
			printf(" %d",short_path[i]);
			if(i){
				printf(" ");
			}
		}
		printf("\n");
	}else{
		//地址 
		printf("Distance = %d:",ans1);
		int len1=short_path.size();
		for(int i=len1-1;i>=0;i--){
			if(i!=len1-1){
				printf("->");
			}
			printf(" %d",short_path[i]);
			if(i){
				printf(" ");
			}
		}
		printf("\n");
		//时间
		printf("Time = %d:",ans2);
		int len2=fast_path.size();
		for(int i=len2-1;i>=0;i--){
			if(i!=len2-1){
				printf("->");
			}
			printf(" %d",fast_path[i]);
			if(i){
				printf(" ");
			}
		}
		printf("\n"); 
	}
	return 0;
}

3. 参考资料

1111. Online Map (30)-PAT甲级真题(Dijkstra + DFS)_柳婼的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值