PAT 团体程序设计天梯赛-练习集 题解(凑零钱,堆栈,社交集群)

开始准备cccc(cry)天梯赛了,第一周训练题,把官网挂出的训练题刷完了,对pat有了一点点的熟悉感。

L1-1  就不说了。。。

L1-2 打印沙漏 

一个变量保存空格数,一个变量保存沙漏符号数,打印就行了,但这题话说wrong好几次啊,坑点是沙漏符号后面不打印空格,orz。。。


<span style="font-size:14px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main(){
	int n;
	char c;
	scanf("%d %c",&n,&c);
	int a[1010];
	a[0] = 0;
	a[1] = 1;
	for(int i=2;i<1010;i++){
		a[i] = a[i-1] + (2*i - 1)*2;
	}
	int t = 0;
	for(;t<1010;t++){<span style="white-space:pre">		</span>//找到最大一层
		if(n<a[t])	break;
	}
	t--;
	int z = 0;
	for(int i=t;i>=1;i--){<span style="white-space:pre">	</span>//打印上一半
		for(int j=0;j<z;j++){
			printf(" ");
		}
		for(int j = 0;j<(i*2-1);j++){
			printf("%c",c);
		}
		
		z++;
		printf("\n");
	}
	z-=2;<span style="white-space:pre">		</span>//中间只有一个
	for(int i=2;i<=t;i++){<span style="white-space:pre">	</span>//打印下一半
		for(int j=0;j<z;j++){
			printf(" ");
		}
		for(int j = 0;j<(i*2-1);j++){
			printf("%c",c);
		}
		
		z--;
		printf("\n");
	}
	printf("%d\n",n-a[t]);
	
	return 0;
}</span>

L1-3 个位数统计   取余一下就行


<span style="font-size:14px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main(){
	int a[11];
	memset(a,0,sizeof(a));
	char n[1010];
	scanf("%s",n);
	int len = strlen(n);
	if(len==1&&n[0]=='0')	a[0]++;
	while(len){
		a[n[--len]-'0']++;
	}
	for(int i=0;i<10;i++){
		if(a[i]){
			printf("%d:%d\n",i,a[i]);
		}
	}
	
	return 0;
}</span>


L1-4  计算摄氏温度

怎么感觉在凑字数。。。


<span style="font-size:14px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main(){
	int n;
	scanf("%d",&n);
	printf("Celsius = %d\n",5*(n-32)/9);
	return 0;
}</span>

L1-5  考试座位号


hash,用了map,对应一下就行


<span style="font-size:14px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
#include<map>
#include<string>
using namespace std;
int main(){
	int N;
	scanf("%d",&N);
	map<int ,string>m;
	int c[1010];
	for(int i=0;i<N;i++){
	string n;
	int a,b;
	cin>>n>>a>>b;
	m[a] = n;
	c[a] = b;
	}
	int n;
	scanf("%d",&n);
	while(n--){
		int temp;
		scanf("%d",&temp);
		cout<<m[temp]<<' '<<c[temp]<<endl;
	}
	
	return 0;
}</span>

L1-6 连续因子


暴力的解法,从改数的平方根开始先前查找,当该次查找结束且长度比之前长则更新,因为从后往前扫,保证更新的数为最小

<span style="font-size:14px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main(){
	int N;
	scanf("%d",&N);
	int n = 0;
	char a[1010];
	char temp[1010];
	int tn = 0;
	int status = 1;
	for(int i = (int)sqrt(N)+1;i>=2&&status;i--){
		tn = 0;
		if(N%i==0){
			temp[tn++] = i;
			int t = N/i;
			for(int j = i-1;j>=2;j--){
				if(t%j==0){
					temp[tn++] = j;
					t/=j;
					if(j==2){
						status = 0;
					}
				}
				else{
					temp[tn] = 0;
					break;
				}
			}
			if(tn>=n){
				strcpy(a,temp);
				n = tn;
			}
		}
	}
	if(n==0){
		printf("%d\n%d\n",n+1,N);
	}
	else{
		printf("%d\n",n);
		for(int j=n-1;j>=0;j--){
			printf("%d",a[j]);
			if(j!=0){
				printf("*");
			} 
			else{
				printf("\n");
			}
		}
	}
	return 0;
}</span>


L1-7  念数字

字符串存储,对应即可


<span style="font-size:18px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
#include<string>
using namespace std;
char a[10][10] = {"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};

int main(){
	string s;
	cin>>s;
	int len = s.size();
	int i=0;
	if(s[i]=='-'){
		printf("fu ");
		i++;
	}
	for(;i<len;i++){
		printf("%s",a[s[i]-'0']);
		if(i!=len-1){
			printf(" ");
		}
		else{
			printf("\n");
		}
	}
	return 0;
}</span><span style="font-size:24px;">
</span>

L1-8  求整数段和

打印数字一个变量记行,一个变量计数

求和  要考虑正数和负数

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	int n = b-a+1;
	for(int i=0;i<n;i++){
		int temp = a+i;
		int time = 5;
		if(temp<=0){
			time--;
		} 
		while(temp){
			time--;
			temp/=10;
		}
		for(int i=0;i<time;i++){
			printf(" ");
		}
		printf("%d",a+i);
		if((i+1)%5==0){
			printf("\n");
		}
		
	}
	if(n%5!=0){
			printf("\n");
		}
		
	if(a>=0||b<=0){
			printf("Sum = %d\n",(b-a+1)*(b+a)/2);
		}
		else{
			printf("Sum = %d\n",(b-0+1)*(b+0)/2 + (0-a+1)*(0+a)/2);
		}
	return 0;
}

L2-1   紧急救援

求最短路径,使用广度优先搜索,要求输出最短路径的条数和路径。

最短路并且要求救援队的数量最多,那么使用优先队列,按照步数来进行排序,相同步数则救援队数量最多,则当广度优先搜索搜索到目的地时,求得的步数为结果,当步数大于已求得的结果,则搜索结束。

路径使用数组保存,每搜索一个点,与当前已标记的点去比较,步数最小且救援队数量最多则更新路径数组,路径输出则从D查找到S即可


#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
#include<queue>
using namespace std;
int c[510];	//每个城市的救援队数量
int a[510][510];	//存储步数
int book[510];		//记录路径
int cunt;
int step;
int ttime;
struct node{
	int c;		//救援队
	int s;		//步数
	int n;	//当前节点
	int o;	//前一个节点
	bool operator <(const node& x) const{			//优先级:先排列步数,再排列救援队数目
	if(s==x.s){
		return c<x.c;
	}
	else{
		return s>x.s;
	}
	} 
};
	int N,M,S,D;
	void serach(int t);
	void fin();
int main(){

	scanf("%d%d%d%d",&N,&M,&S,&D);
	for(int i=0;i<N;i++){
		scanf("%d",&c[i]);
		book[i] = -1;
	}
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			a[i][j] = -1;	//没有联通   为-1
		}
	}
	while(M--){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		a[x][y] = a[y][x] = z;
	}
	step = 11111111;		//最后步数结果
	cunt = 11111111;		//最后救援队数量结果
	ttime = 0;				//最短路径数量
	fin();					//广搜
	printf("%d %d\n",ttime,cunt);
	serach(D);			//输出路径
	printf("\n");
	
	return 0;
}
//输出路径(递归)
void serach(int t){
	if(t==S){
		printf("%d",S);
		return ;
	}
	serach(book[t]);
	printf(" %d",t);
}

void fin(){
	node p;		//起始点
	p.o = S;
	p.n = S;
	p.c = c[S];
	p.s = 0;
	priority_queue<node> q;	//优先队列
	q.push(p);	
	while(!q.empty()){
		node t = q.top();
		q.pop();
		if(book[t.n]<0){	//记录路径
			book[t.n] = t.o;
		}
		if(t.s>step)	{	//已求得结果,退出
			return ;
		}
		else if(t.n==D&&t.s==step){		//最短路径计数
			ttime++;
		}
		else if(t.n==D){			//最优路径
			step = t.s;
			ttime++;
			cunt = t.c;
		}
		
		node temp;
		temp.o = t.n;
		
		for(int i=0;i<N;i++){			//广搜
			if(book[i]<0&&a[t.n][i]>=0){		//未广搜且联通
				temp.n = i;
				temp.c = t.c+c[i];
				temp.s = t.s + a[t.n][i];
				q.push(temp);
				
			}
		}
	}
}

L2-2   链表去重

本体借鉴feng同学思路,感谢^_^

把所有点保存,设一个标记数组,从头结点开始,若当前点值未存在,存进一个数组,否则存进另一个,最后顺序输出即可。注意输出,从第二个节点开始要输出两遍自身地址,因为前后有可能地址并不对应。

输出技巧:%05d  即可输出5位,前面补0


#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<map>
#include<algorithm>
using namespace std;
struct node{
	int key;
	int next;
}a[100005];
char book[10005];
int o[100005];
int s[100005];
int on,sn;
int main(){
	int S,N;
	scanf("%d%d",&S,&N);
	for(int i=0;i<N;i++){
		int p;
		scanf("%d",&p);
		scanf("%d%d",&a[p].key,&a[p].next);
	}
	sn = 0,on = 0;
	memset(book,0,sizeof(book));
	for(int i=0;i<N&&S!=-1;i++){
		if(!book[abs(a[S].key)]){
			o[on++] = S;
			book[abs(a[S].key)] = 1;
			S = a[S].next;
		}
		else{
			s[sn++] = S;
			S = a[S].next;
		}
	}
	if(on){
		for(int i=0;i<on;i++){
			if(i==0){
				printf("%05d %d",o[i],a[o[i]].key);
			}
			else{
				printf(" %05d\n%05d %d",o[i],o[i],a[o[i]].key);
			}
		}
		printf(" -1\n");
	}
	if(sn){
		for(int i=0;i<sn;i++){
			if(i==0){
				printf("%05d %d",s[i],a[s[i]].key);
			}
			else{
				printf(" %05d\n%05d %d",s[i],s[i],a[s[i]].key);
			}
		}
		printf(" -1\n");
	}
	
	return 0;
}

L2-3   月饼


排下序,计算就可以了,注意精度


#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
struct node{
	double num;
	double mon;
	bool operator <(const node& x)const{
		return mon*x.num>num*x.mon?1:0;<span style="white-space:pre">		</span>//没有用除法,把分数化成同分母比较,会减少误差
	}
};
int main(){
	int n;
	double m;
	node a[1010];
	scanf("%d%lf",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%lf",&a[i].num);
	}
	for(int i=0;i<n;i++){
		scanf("%lf",&a[i].mon);
	}
	sort(a,a+n);
	double sum = 0;
	for(int i=0;i<n;i++){
		if(m==0)	break;
		if(m>=a[i].num){			//最后的错误点  ’= ’  精度要求很高! 
			sum += a[i].mon;
			m-=a[i].num;
		}
		else if(m>0&&m<a[i].num){
			sum += (a[i].mon*m/a[i].num);
			break;
		}
		
	}
	printf("%.2lf\n",sum);
	return 0;
}

L2-4   这是二叉搜索树吗?

建树了,建一颗正常搜索树,再建一颗镜像搜索树,分别比较是否符合即可

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
struct node{
  int k;
  struct node* left;
  struct node* right;
};
  int N;
  int a[1010];
  int tt[1010];
  struct node* tree1;
  struct node* tree2;
  void pos(struct node* t);
  void pre(struct node* t,int& x);
  struct node* init1(struct node* t,int v);//正常
  struct node* init2(struct node* t,int v);//镜像
  
int main(){
  scanf("%d",&N);
  tree1 = tree2 = NULL;
  for(int i=0;i<N;i++){
    scanf("%d",&a[i]);
    tree1 = init1(tree1,a[i]);
    tree2 = init2(tree2,a[i]);
  }
  int x = 0;
  pre(tree1,x);<span style="white-space:pre">	</span>//前序
  int status = 0;
  for(int i=0;i<N;i++){//比较
    if(tt[i]!=a[i]){
      status = 1;
      break;
    }
  }
  if(status){
    x = 0;
    pre(tree2,x);//后序
    status = 0;
    for(int i=0;i<N;i++){
    if(tt[i]!=a[i]){
      status = 1;
      break;
    }
    }
    if(status==0){
      printf("YES\n");
      pos(tree2);
    }
    else{
      printf("NO\n");
    }
  }
  else{
    printf("YES\n");
    pos(tree1);
  }
  return 0;
}
//输出路径
void pos(struct node* t){
  if(t==NULL)  return ;
  pos(t->left);
  pos(t->right);
  if(t==tree1||t==tree2){
    printf("%d\n",t->k);
  }
  else{
    printf("%d ",t->k);
  }
}
//前序
void pre(struct node* t,int& x){
  if(t!=NULL&&x<N){
    tt[x] = t->k;
    x++;
    pre(t->left,x);
    pre(t->right,x);
  }
}
struct node* init1(struct node* t,int v){
  if(t==NULL){
    t = (struct node*)malloc(sizeof(struct node));
    t->k = v;
    t->left = t->right = NULL;
    return t;
  }
  if(v<t->k){
    t->left = init1(t->left,v);
  }
  else{
    t->right = init1(t->right,v);
  }
  return t;
}

struct node* init2(struct node* t,int v){
  if(t==NULL){
    t = (struct node*)malloc(sizeof(struct node));
    t->k = v;
    t->left = t->right = NULL;
    return t;
  }
  if(v>=t->k){
    t->left = init2(t->left,v);
  }
  else{
    t->right = init2(t->right,v);
  }
  return t;
}

L3-1    凑零钱

普通01背包,装满背包,dp[]中保存用的零钱个数,零钱用的越多,肯定数最小,我排了下序,好像不排序也可以

dfs强剪枝也可以

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int book[110];<span style="white-space:pre">	</span>//路径
int v[110];<span style="white-space:pre">	</span>//用于路径中比较值
void input(int x);//输出,我起错名了。。。
int main(){
  int N,M;
  int a[10010];
  scanf("%d%d",&N,&M);
  for(int i=0;i<N;i++){
    scanf("%d",&a[i]);
  }
  int dp[110];
  
  sort(a,a+N);
  for(int i=0;i<=M;i++){
    dp[i] = -0x3f3f3f3f;<span style="white-space:pre">	</span>//注意装满应该为无穷小
    book[i] = -1;
  }
  dp[0] = 0;
  for(int i=0;i<N;i++){
    for(int j=M;j>=a[i];j--){
      if(dp[j]<=dp[j-a[i]]+1){
        dp[j] = dp[j-a[i]]+1;
        book[j] = j-a[i];
        v[j] = a[i];
      }
    }
  }
  if(dp[M]>0){
    input(M);
    printf("\n");
  }
  else{
    printf("No Solution\n");
  }
  
  return 0;
}

void input(int x){
  if(book[x]==0){
    printf("%d",v[x]);
    return ;
  }
  input(book[x]);
  printf(" %d",v[x]);
}

L3-2    堆栈


单点更新查询,用线段树,保存本区间内的点数


#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stack>
#define lson l,m,level*2
#define rson m+1,r,level*2+1
using namespace std;
int a[100010];
int tree[100010*5];
void init(int l,int r,int level);
void find(int l,int r,int level,int x);
void update(int l,int r,int level,int x,int s);
int main(){
	int N;
	scanf("%d",&N);
	stack<int>s;
	getchar();
	int mmax = 100002;
	memset(a,0,sizeof(a));
	memset(tree,0,sizeof(tree));
	//init(1,100000,1);
	while(N--){
		char c[30];
		int num;
		scanf("%s",c);
		if(!strcmp(c,"Pop")){
			if(!s.empty()){
				printf("%d\n",s.top());
				update(1,mmax,1,s.top(),0);
				a[s.top()]--;
				s.pop();
				
			}
			else{
				printf("Invalid\n");
			}
		}
		else if(!strcmp(c,"PeekMedian")){
			int n = s.size();
			if(n>0){			
				if(n%2==1){<span style="white-space:pre">		</span>//注意奇偶数
					n++;
				}
				find(1,mmax,1,n/2);
			}
			else{
				printf("Invalid\n");
			}
		}
		else if(!strcmp(c,"Push")){
			scanf("%d",&num);
			s.push(num);
			a[num]++;
			if(mmax<num){		//这里mmax会出错(应该是线段树的N是确定的,而不是不确定的,memory) 
				mmax = num;
			}
			update(1,mmax,1,num,1);
		}
	}
}

void update(int l,int r,int level,int x,int b){
	if(l==r&&x==l){
		if(b==0)
		tree[level]--;
		else
		tree[level]++;
		return ;
	}
	int m = (l+r)>>1;
	if(x<=m){
		update(lson,x,b);
	}
	else{
		update(rson,x,b);
	}
	tree[level] = tree[level*2+1] + tree[level*2];
}


void find(int l,int r,int level,int x){
	if(l==r&&(x<=tree[level])){
		printf("%d\n",l);
		return ;
	}
	int m = (l+r)>>1;
	if(tree[level*2]>=x){
		find(lson,x);
	}
	else{
		find(rson,(x-tree[level*2]));
	}
}

void init(int l,int r,int level){
	if(l==r){
		tree[level] = a[l];
		return ;
	}
	int m = (l+r)>>1;
	init(lson);
	init(rson);
	tree[level] = tree[level*2] + tree[level*2+1];
}

L3-3    社交集群

vector数组为活动号,保存选择该活动的人员编号。从第一个人i开始查找,所有和本人在同一活动中的人全部入队,并标记上i,并对队的每个人进行相同查找,直到队空。i++,在进行下一个没有查找过的人的查找到结束。

最后计算标记数组中共出现的标号和数量,排序输出。


#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
vector <int >a[1010];
int main(){
	int N;
	scanf("%d",&N);
	int mmax = 0;
	for(int i=1;i<=N;i++){
		int n;
		scanf("%d:",&n);
		for(int j=0;j<n;j++){
			int num;
			scanf("%d",&num);
			if(mmax<num){
				mmax = num;
			}
			a[num].push_back(i); 
		}
	}
	int x[1010],y[1010];//x:person   y:problem
	memset(x,0,sizeof(x));
	memset(y,0,sizeof(y));
	for(int i=1;i<=N;i++){//ren
		if(!x[i]){
			x[i] = i;
			queue<int>q;
			q.push(i);
			while(!q.empty()){
				int p = q.front();
				q.pop();
				for(int j=0;j<=mmax;j++){
					if(a[j].size()!=0&&!y[j]&&find(a[j].begin(),a[j].end(),p)!=a[j].end()){
						y[j] = 1;
						for(int k=0;k<a[j].size();k++){
							if(!x[a[j][k]]){
								x[a[j][k]] = i;
								q.push(a[j][k]);
							}
						}
						
					}
				}
			}
		}
	}
	int c[1100];
	memset(c,0,sizeof(c));
	for(int i=1;i<=N;i++){
		c[x[i]]++;
	}
	sort(c,c+N+10,greater<int>());
	int time = 0;
	for(int i=0;c[i];i++){
		time++;
	}
	printf("%d\n",time);
	if(time){
		printf("%d",c[0]);
	for(int i=1;c[i];i++){
		printf(" %d",c[i]);
	}
	printf("\n");
	}
	
	return 0;
}

你可能感兴趣的:(pat,团体程序设计天梯赛)