[PAT Basic Level] 1085~1089

1085. PAT单位排行

题目分析:

这道题某些思想和1080很像,为了快速查找相同学校,我们可以先对整个数组进行排序,按学校的校名字典序升序排序,这样相同的校名就会在一起,就可以方便地统计人数以及总分。这里我的代码可能看起来有些绕,因为最开始有两个点超时了,放下了过了几天才回头改,有些变量名很相似,不容易区分。

源代码

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
struct grades{
	char schID[7];
	double totScore=0.0;
	int weight_tot,number=0;
};
struct info{
	char id[7];
	int score;
	char schName[7];
};
void update(const info& p,grades& g){
	char rank=p.id[0];
	if(rank=='A') g.totScore+=p.score;
	else if(rank=='B') g.totScore+=p.score/1.5;
	else g.totScore+=p.score*1.5;
	g.number++;  //人数+1 
}
bool cmp1(const info& p1,const info& p2){
	return strcmp(p1.schName,p2.schName)<0; //按校名字典升序排列 
}
bool cmp2(const grades&t1,const grades& t2){
	if(t1.weight_tot!=t2.weight_tot) return t1.weight_tot>t2.weight_tot;
	if(t1.number!=t2.number) return t1.number<t2.number;  //人数升序输出
	return strcmp(t1.schID,t2.schID)<0;  //按字典升序排列 
} 

int main(){
	int num;
	scanf("%d",&num);
	grades* list=new grades[num];
	info *infoList=new info[num]; 
	for(int i=0;i<num;++i){
		scanf("%s %d %s",infoList[i].id,&infoList[i].score,infoList[i].schName);
		int len=strlen(infoList[i].schName);
		for(int j=0;j<len;++j) 
			infoList[i].schName[j]=tolower(infoList[i].schName[j]);  //转换成小写
	}
	std::sort(infoList,infoList+num,cmp1);
	int count=0;//不同学校的数目,实际上会少1 
	char prename[7];
	strcpy(prename,infoList[0].schName);
	strcpy(list[count].schID,prename);
	update(infoList[0],list[count]);
	for(int i=1;i<num;++i){
		if(strcmp(infoList[i].schName,prename)!=0){//发现新学校 
			strcpy(list[++count].schID,infoList[i].schName);
			strcpy(prename,infoList[i].schName);
		}
		update(infoList[i],list[count]);   
	}
	count++;  //这样 count就表示了不同学校的数目 
	for(int i=0;i<count;++i)
		list[i].weight_tot=list[i].totScore;  //加权平均后保留整数部分 
	std::sort(list,list+count,cmp2);
	printf("%d\n",count);
	int preOrder=1;
	printf("%d %s %d %d\n",preOrder,list[0].schID,list[0].weight_tot,list[0].number);
	for(int i=1;i<count;++i){
		if(list[i].weight_tot<list[i-1].weight_tot) preOrder=i+1;  //非并列时 
		printf("%d %s %d %d\n",preOrder,list[i].schID,list[i].weight_tot,list[i].number);
	} 
	delete []infoList; 
	delete []list;
	return 0; 
} 

1086. 就不告诉你

题目分析:

(题目的图片我感觉很熟悉啊,是不是放牛班的春天里的?)
题目给的数据范围乘法完全不会溢出可以安心用int,倒着输出结果也不麻烦,用一个数组从低到高储存各位就好了,不过在输出时记得要先找到非零的第一项再开始输出。

源代码

#include <cstdio>

int main()
{
	int n1,n2,mul,count=0;
	int result[7];  //不超过7位数
	scanf("%d %d",&n1,&n2);
	mul=n1*n2;
	while(mul){
		result[count++]=mul%10;
		mul/=10;
	}
	int j=0; 
	while(result[j]==0) j++;  //找到第一个非零项 
	for(int i=j;i<count;++i)
		printf("%d",result[i]);
	return 0;
 } 

1087. 有多少不同的值

题目分析:

首先计算出给定值能算出来的最大情况,设为MAX吧,开一个大小为MAX的int数组来储存各个值是否出现。
再遍历一遍,把非零的元素对应的下标输出出来就可以了。

源代码

#include <cstdio>

int main()
{
	int num;
	scanf("%d",&num);
	int upperBound=num*31/30;  //至多出现不同值的可能性个数 
	int *valueList=new int[upperBound+1];   //由于不使用0,所以开辟数组大小要+1 
	for(int i=0;i<upperBound+1;++i) valueList[i]=0;
	for(int i=1;i<=num;++i){
		int tmp=(i>>1)+i/3+i/5;
		valueList[tmp]++;
	}
	int count=0;
	for(int i=0;i<upperBound+1;++i)
		if(valueList[i]>0) count++;
	printf("%d",count);
	delete []valueList;
	return 0;
 } 

1088. 三人行

题目分析:

有点解方程的意思,但是这里我们并不去解它,而是采用暴力穷举的方法来找到有效解。
这里需要注意,题目中的丙的能力值不一定是整数,只要满足条件就可以了,所以要用double存储。在判断方程是否成立时需要满足:
∣ P 甲 − P 乙 ∣ x = P 乙 y \frac{|P_甲-P_乙|}{x}=\frac{P_乙}{y} xPP=yP
遍历甲、乙能力值时,由于他们都是整数,那么当然不能直接用上面的式子,否则会由于舍入情况不同造成即使数学上不相等程序仍判定为等于,一种解决方法是用 ∣ P 甲 − P 乙 ∣ ∗ y = P 乙 ∗ x |P_甲 -P_乙|*y=P_乙 *x PPy=Px来判断,这样都是整数运算,是可行的。我之前采用了另一种计算方法: ∣ P 甲 − P 乙 ∣ = ( P 乙 ∗ x ) / y |P_甲 -P_乙|=(P_乙 *x)/y PP=(Px)/y,但这样答案却不对,而这里显然乘法是不会溢出的,数学上完全等价程序上也不会有截断误差,为何代码却不对呢?如果有人知道还希望指点一下。

源代码

#include <cstdio>
#include <cstdlib>
int main()
{
	int myPower,x,y;
	scanf("%d %d %d",&myPower,&x,&y);
	int p2,p3;  //表示p甲和p乙的能力值
	double final[3];  //最终应取的甲、乙、丙值 
	final[0]=-1.0;  //甲初始化为-1,为了以后寻找甲最大可行解 
	for(p2=99;p2>9;--p2){  //遍历寻找所有可能解 
		p3=(p2%10)*10+p2/10;  //求出p乙
		if(abs(p2-p3)*y==p3*x){ //找到满足要求的值  这里写abs(p2-p3)=(p3*x)/y却不行,why? 
			final[0]=p2;final[1]=p3;final[2]=final[1]/y;
			printf("%d",p2);  //输出甲的值 
			for(int i=0;i<3;++i){
				if(final[i]>(double)myPower) printf(" Cong");
				else if(final[i]<(double)myPower) printf(" Gai");
				else printf(" Ping");
			}
			break; 
		} 
	} 
	if(final[0]<0.0)
		printf("No Solution");
	return 0;
} 

1089. 狼人杀-简单版

题目分析:

这个简单版狼人杀,开始思路不太对,很繁琐,但是想清楚后就会很清晰。没什么很好的办法,题目给定的数据范围也不大,那就蛮力穷举吧,但穷举狼人的位置还是撒谎者的位置呢?这里显然穷举狼人的位置更好,因为题目要求我们如果出现多个解,按狼人位置序号尽量小来输出,那么如果穷举狼人位置的话从小往大试,发现一个解立即输出就好了。

源代码

#include <iostream>
#include <cstdlib>
#include <vector> 
int main()
{
	using namespace std;
	int num;
	scanf("%d",&num);
	vector<int> speech(num+1); 
	for(int i=1;i<num+1;++i)  //注意从1开始,0号不用 
		scanf("%d",&speech[i]);
	bool find=false;  //发现可行解标志 
	for(int wolv1=1;wolv1<num;++wolv1){
		for(int wolv2=wolv1+1;wolv2<num+1;++wolv2){
			vector<int> truth(num+1,1);
			truth[wolv1]=truth[wolv2]=-1;
			int liar=0;  //统计撒谎者数目
			bool wolv_liar=false;  //狼人撒谎标志,一个狼人撒谎则为true,否则为false  
			for(int i=1;i<num+1;++i){
				if(speech[i]*truth[abs(speech[i])]<0){ //表明此人撒谎了 
					liar++;
					if(i==wolv1||i==wolv2){ //发现狼人撒谎
						if(wolv_liar) wolv_liar=false;  
						else wolv_liar=true; 
					}
				}
			}
			if(liar==2&&wolv_liar){
				printf("%d %d",wolv1,wolv2);
				return 0;
			}
		}
	}
	printf("No Solution");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值