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

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

L1-1  就不说了。。。

L1-2 打印沙漏 

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


#include
#include
#include
#include
#include
#include
#include
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++){		//找到最大一层
		if(n=1;i--){	//打印上一半
		for(int j=0;j		//中间只有一个
	for(int i=2;i<=t;i++){	//打印下一半
		for(int j=0;j

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


#include
#include
#include
#include
#include
#include
#include
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;
}


L1-4  计算摄氏温度

怎么感觉在凑字数。。。


#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main(){
	int n;
	scanf("%d",&n);
	printf("Celsius = %d\n",5*(n-32)/9);
	return 0;
}

L1-5  考试座位号


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


#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main(){
	int N;
	scanf("%d",&N);
	mapm;
	int c[1010];
	for(int i=0;i>n>>a>>b;
	m[a] = n;
	c[a] = b;
	}
	int n;
	scanf("%d",&n);
	while(n--){
		int temp;
		scanf("%d",&temp);
		cout<

L1-6 连续因子


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

#include
#include
#include
#include
#include
#include
#include
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;
}


L1-7  念数字

字符串存储,对应即可


#include
#include
#include
#include
#include
#include
#include
#include
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

L1-8  求整数段和

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

求和  要考虑正数和负数

#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	int n = b-a+1;
	for(int i=0;i=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
#include
#include
#include
#include
#include
#include
#include
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 cx.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 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=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
#include
#include
#include
#include
#include
#include
#include
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

L2-3   月饼


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


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

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

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

#include
#include
#include
#include
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	//前序
  int status = 0;
  for(int i=0;ileft);
  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&&xk;
    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(vk){
    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
#include
#include
#include
using namespace std;
int book[110];	//路径
int v[110];	//用于路径中比较值
void input(int x);//输出,我起错名了。。。
int main(){
  int N,M;
  int a[10010];
  scanf("%d%d",&N,&M);
  for(int i=0;i	//注意装满应该为无穷小
    book[i] = -1;
  }
  dp[0] = 0;
  for(int i=0;i=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
#include
#include
#include
#include
#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);
	stacks;
	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){		//注意奇偶数
					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>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
#include
#include
#include
#include
#include
#include
using namespace std;
vector 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;jq;
			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());
	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)