【睛神PAT】PAT训练 0222-0228

0222-1图形编程— [PAT B1036] 奥巴马编程

#include<stdio.h>
int main(){
	int num,col;
	char ch;
	scanf("%d %c",&num,&ch);
//	#确定行数 
	if(num%2==1)
		col=num/2+1;
	else
		col=num/2;
	for(int i=0;i<col;i++){
//		#如果为第一行或者最后一行 
		if(i==0||i==col-1){
		for(int j=0;j<num;j++)
			printf("%c",ch);	
		}
//		#如果为中间行 
		else{
		for(int j=0;j<num;j++)
			if(j==0||j==num-1)
			printf("%c",ch);
			else
			printf(" ");
		}
//		#非最后行转下一行 
		if(i!=col-1)
			printf("\n");
		}
	} 

【问题分析】

  • (看懂题) 问题是怎么把中间行表示,问题出现在中间行以为要表示空行,其实不用,只需要对应输入
  • 四舍五入表示,偶数直接除2,奇数为/2+1

0222-2日期处理— [计算日期差值]

输入两个日期如:
20130101
20130105
计算日期差值

#include<stdio.h>
//平年和闰年的每个月的天数
int month[13][2]={
	{0,0},
	{31,31},{28,29},{31,31},{30,30},
	{31,31},{30,30},{31,31},{31,31},
	{30,30},{31,31},{30,30},{31,31},
}
//判断是否是闰年
bool isLeap(int year){
	return(year%4==0&&year%100!=0)||(year%400==0);
} 
int main(){
	int time1,y1,m1,d1;
	int time2,y2,m2,d2;
	while(scanf("%d%d",&&time1,&time2)!=EOF){
		//保证第一个日期为小日期 
		if(time1>time2){
			int temp=time1;
			time1=time2;
			time2=temp;
		}
		y1=time1/10000,m1=time1%10000/100,d1=time1%100;
		y2=time2/10000,m2=time2%10000/100,d2=time2%100;
		int ans=1; 
		while(y1<y2||m1<m2||d1<d2){
		d1++;
		if(d1==month[m1][isLeap(y1)]+1){//满当月天数 
			m1++;
			d1=1;
		} 
		if(m1==13){//满年 
			y1++;
			m1=1;
		} 
		ans++;
	}
	printf("%d\n",ans);
	return 0;
}

【问题分析】

  • 1、全部累加表示对应天数,直到达到所要求的日子 (用静态数组预先存储对应的值)

  • 2、怎么去输入对应的值去处理 (直接用int表示)

  • 3、怎么完成对应的日子转换 (通过对应的累加进位的方式)

【PAT B1028】人口普查

日期类题目有两种,一种是计算两个日期之间的差值,另一种是比较
如果不要求对应的具体时间,在有效性方面之后,可以仅通过每一位的比较的方式进行对应比对

#include<cstdio>
//oldest——最老的;
//youngest——最年轻的;
//left——下界;
//right——上界;
//temp——临时变量
struct person{
    char name[10];
    int yy,mm,dd;
}oldest,youngest,left,right,temp;

//如果a的日期小于等于b的日期,return true
bool LessEqu(person a,person b){
    if(a.yy!=b.yy)
        return a.yy<=b.yy;
    else if(a.mm!=b.mm)
        return a.mm<=b.mm;
    else 
        return a.dd<=b.dd;
}
//如果a的日期大于等于b的日期,return true
bool MoreEqu(person a,person b){
    if(a.yy!=b.yy)
        return a.yy>=b.yy;
    else if(a.mm!=b.mm)
        return a.mm>=b.mm;
    else 
        return a.dd>=b.dd;
}
//初始化最年轻和最老
void init(){
    youngest.yy=left.yy=1814;
    oldest.yy=right.yy=2014;
    youngest.mm=left.mm=oldest.mm=right.mm=9;
    youngest.dd=left.dd=oldest.dd=right.dd=6;
}
int main(){
    init();
    int N,num=0;
    scanf("%d",&N);
    for(int i=0;i<N;i++){
        scanf("%s %d/%d/%d",temp.name,&temp.yy,&temp.mm,&temp.dd);
        if(MoreEqu(temp,left)&&LessEqu(temp,right)){
            num++;
            if(LessEqu(temp,oldest)) oldest=temp;
            if(MoreEqu(temp,youngest))youngest=temp;
        }

    }
    if(num==0)
    printf("0\n");
    else 
    printf("%d %s %s\n",num,oldest.name,youngest.name);
}

【问题分析】

  • 1、活用结构体表示信息的整合
  • 2、活用全局变量进行具体表示对应的信息
  • 3、进行对应的比较时可以仅通过每一个度量单位的对比

0222-3 进制处理—【PAT B1022】D进制的A+B

预先知识

1、P进制x转换10进制y——乘法转换

//总结:每一位取,每一位拿,进制进位
int y=0,product=1;
while(x!=0){
	y=y+(x%10)*product;		//x%10获取x的个数位
	x=x/10;					//去掉x的个数位
	product=product*P;
	}

2、10进制y转换位Q进制x——除法转换

//z存放余数
int z[40],num=0;
//取余实质反序存放
do{
z[num++]=y%Q;
y=y/Q;
}while(y!=0);
//再逆序输出即为对应所要求的值
for(int i=num-1;i>=0;i--){
//其实可以直接输出不用再保存了
//printf("%d",z[i]);
x*=10;
x+=z[i];
}
printf("%d",x);

PAT答案

#include<stdio.h>
int main(){
	int a,b,d=0;
	int P;
	scanf("%d %d %d",&a,&b,&P);
	int an=a+b;
	int z[32];
	int num=0;
	do{
		z[num++]=an%P;
		an/=P;
	}while(an!=0);
	for(int i=num-1;i>=0;i--){
		printf("%d",z[i]);
			
	}
	return 0;
}

【问题分析】

  • 1、10进制转P进制,用除解决,反向输出
  • 2、P进制转10进制,用乘解决,输出即可

0222-4 字符串处理—【PAT B1009】说反话

回文串处理(保证正向读和逆向读一致)

#include<cstdio>
#include<cstring>
int maxn=255; 
//回文串的判断 
bool judge(char str[]){
	int len=strlen(str);
	for(int i=0;i<=len/2;i++)
	if(str[i]!=str[len-1-i])
		return false;
	}
int main(){
	char str[maxn];
	while(gets(str)){
		bool flag=judge(str);
		if(flag==true)
		printf("YES\n");
		else
		printf("NO\n")l
	}
	return 0;
}

正文:说反话

方法一:针对对应的gets方法存储

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=255;
int main(){
    char str[maxn];
//由于pat不支持gets,如果要用到读取字符串的时候引入iostream,和using namespace std 用cin的方式进行对应计算
    cin.getline(str,90);
    int len=strlen(str);
    //设置每一个单词的开始和结束
    int start,end;
    //遍历读取的对应句子
    for(int i=len-1;i>=0;i--){
    	//每一个单词的末尾位置
        start=i;
        //当读到这个句子头时进行的操作减1
        while(str[i]!=' '&&i!=0)
        i--;
        //根据读到的不同情况,确定开始位置的详细描述
        if(i==0)
        end=i;
        else 
        end=i+1;
        //根据单词的开头和结尾位置输出对应的值
        for(int j=end;j<=start;j++)
        printf("%c",str[j]);
        //间隔单词
        if(end!=0)
        printf(" ");
    }
    return 0;
}

方法而:针对对应的scanf方法存储

#include<stdio.h>
int main(){
char an[90][90];
int i=0;
while(scanf("%s",an[i])!=EOF){
	i++;
	}
    i=i-1;
for(;i>=0;i--){
	printf("%s",an[i]);
	if(i>0)printf(" ");
	}
	return 0;
	}

【问题分析】

  • 1、字符串的输入是首先建立对应的str数组
  • 2、 在对应的输入字符串过程中可以依据的方法可以采用两种方式:
    gets//cin.getline — 读一整个行,进行存储
    scanf(“%s”,str)进行单独的遇空格则停止的存储
  • 3、字符串的长度函数strlen为实际有值的存放长度

0222小结

编号内容状态数目
0查找元素复习PB 2
1图形编程新学C 1
2日期处理新学PB 1
3进制表示新学PB 1
4字符串新学PB 1+C1

总计 PB:5 C:2

0223专题——排序

[0]冒泡排序

void bubbleSort(){
//A[n]
	//进行第几趟排序
	for(int i=1;i<=n-1;i++){
		//每次换的起始和终止位置
		for(int j=0;j<=n-i-1;j++){
		if(A[j]>A[j+1]){
			int temp=A[j];
			A[j]=A[j+1];
			A[j+1]=temp;
			}
		}
	}
}

[1]简单选择排序

void selectSort(){
//A[n]
	//进行第几趟排序
	for(int i=1;i<=n-1;i++){
	int k=i-1;
	//选出i到n中最小的那个
	for(int j=i;j<=n-1;j++){
		if(A[j]<A[k]&&j!=k){
			k=j;
		}
	}
	//选择交换
	int temp=A[i];
	A[i]=A[k];
	A[k]=temp;
	}
}
	

[2]直接插入排序

int A[maxn],n;
void insertSort(){
	//进行n-1趟排序
	for(int i=2;i<=n;i++){
	//temp临时存储A[i],j从i开始往前枚举
	 int temp=A[i],j=i;
	 //进行从后往前遍历
	 while(j>1&&temp<A[j-1]){
	 	A[j]=A[j-1];
	 	j--;
	 	}
	 	A[j]=temp;//插入位置为j
	}
}

[3]sort函数排序

  • A、使用方式头文件
//[1]使用方式
#include<algorithm>
using namespace std;
  • B、具体使用操作
//[2]具体使用
sort(首元素指针,尾元素地址的下一个地址,比较函数)
//如果不写比较函数,默认给出的区间进行递增排序
sort(a,a+4);
//int型,double型均可对应排序,而char型采用字典序的方式进行排序
  • C、cmp函数的使用
    记忆方式 a<b则左小右大;a>b则左大右小。
//[3]cmp使用
bool(int a,int b){
//a>b时,把a放前面
return a>b;
}
sort(a,a+4,cmp);
//int型,double型,char型均可对应排序
  • D、结构体数组排序
//结构体定义
struct node{
int x,y;
}ssd[10];
//对应结构体数组排序
bool cmp(node a,node b){
return a.x>b.x;
}
//如果想要二级排序,首先根据方案1排序后再按照方案2排序
bool cmp(node a,node b){
if(a.x!=b.x)return a.x>b.x;
else return a.y<b.y;
}
  • E、容器排序
  • STL中只有vector、string、deque可以用sort使用,map、set不可以用sort

vector排序

#include<vector>
bool(int a,int b){
//a>b时,把a放前面
return a>b;
}
vector<int>vi;
vi.push_back(3);
vi.push_back(1);
vi.push_back(2);
sort(vi.begin(),vi.end(),cmp);

string排序

#include<string>
string str[3]={"bbbb","cc","aaa"};
sort(str,str+3);//字典序排序

//规定string长度排序
bool cmp(string str1,string str2){
	return str1.length()<str2.length();
	}
sort(str,str+3),cmp;//长度排序

0223小结

编号内容状态数目
0查找元素复习PB 1
1图形编程复习PB 1
2进制表示复习PB 1
3简单数学新学PB 1

总计 PB:4 (短1)

0224小结

编号内容状态数目
0字符串处理复习PB 5

总计 PB:5

0225-1 字符串处理—【PAT B1024】科学计数法

#include<cstdio>
#include<cstring>
int main(){
    char str[10010];
    scanf("%s",str);
    int len=strlen(str);
    //符号输出
    if(str[0]=='-')printf("-");
    int pos=0;
    //E位置记录
    while(str[pos]!='E')
    pos++;
    //exp记录指数不考虑正负
    int exp=0;
    for(int i=pos+2;i<len;i++)
        exp=exp*10+(str[i]-'0');
    //特殊exp情况考虑
    if(exp==0){
        for(int i=1;i<pos;i++)
        printf("%c",str[i]);
    }
    //exp情况的负考虑
    if(str[pos+1]=='-'){
        printf("0.");
        for(int i=0;i<exp-1;i++)
            printf("0");
        printf("%c",str[1]);
        for(int i=3;i<pos;i++)
            printf("%c",str[i]);
    }
    //exp情况的正考虑
    else{
        for(int i=1;i<pos;i++){
            if(str[i]=='.')continue;
            printf("%c",str[i]);
            //这个点是最难想的点,首先要控制i一定是位于exp+2处,但是要考虑是不是就没有点
            //所以要限制一个零界点,保证exp是要不等于E和原小数点之间的数的
            if(i==exp+2&&pos-3!=exp)//可替换为>
            printf(".");
        }
        for(int i=0;i<exp-(pos-3);i++)
           printf("0");
    }
  
    return 0;
}

【问题分析】

  • 1、该问题的真正难度在于怎么去保留有效数字
  • 有时候问题不一定非要转换为数字,再去求,在这里尝试了限制精度的方式,但是发现结果会有误差,并不好
  • 在这里另外一个难点反而是对应正数小数点的输出,采用的方式是具体的判别位置和对应的保证超出了应该没有对应的小数点输出
  • 这里要考虑到pos-3与exp的三个关系:
  • ①、exp比pos-3小-----》输出小数点
  • ②、exp等于pos-3-----》不输出小数点
  • ③、exp比pos-3大-----》补0
  • 但是在循环输出数字的时候它的长度实质上是只能判断第一个和第三个情况

0225-2 【PAT A1025】PAT Ranking

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef struct people{
    char name[15]; //id
    int type;       //类型
    int score;      //分数
    int finalrank;
    int orirank;
}people;
//比较1
bool cmp1(people user1,people user2){
    if(user1.score!=user2.score)
        return user1.score>user2.score;
    else
        return strcmp(user1.name,user2.name)<0;
}
int main(){
    int N,K,index=0;
    people user[30010];
    scanf("%d",&N);
    for(int i=1;i<=N;i++){
        scanf("%d",&K);
        int start=index;
        for(int j=0;j<K;j++){
            scanf("%s",user[index].name);
            scanf("%d",&user[index].score);
            user[index].type=i;
            index++;
        }
        sort(user+start,user+index,cmp1);
        user[start].orirank=1;
        for(int k=start+1;k<index;k++){
            if(user[k].score<user[k-1].score){
                user[k].orirank=k+1-start;
            }
            else{
            	user[k].orirank=user[k-1].orirank;
			}
        }
    }
    sort(user,user+index,cmp1);
    int startscore=user[0].score+1;
    int rank_own=1;
    printf("%d\n",index);
    for(int k=0;k<index;k++){
        if(k>0&&user[k].score!=user[k-1].score)
        rank_own=k+1;
            printf("%s %d %d %d",user[k].name,rank_own,user[k].type,user[k].orirank);
            // if(k!=index-1)
            printf("\n");
        }
    
    return 0;
}

【问题分析】

  • 1、排名的变化可以体现在是否与上一个相同,如果相同则为同样的排名,如果不同则在自己的index基础上+1

0225-3专题 最大公约数与最小公倍数

1、最大公约数问题——辗转相除法

gcd(a,b)=gcd(b,a%b)

  • 递归式: gcd(a,b)=gcd(b,a%b)
  • 递归边界:gcd(a,0)
int gcd(int a,int b){
	if(b==0)
		return a;
	else
		return gcd(b,a%b);
}

2、最小公倍数问题——建立在最大公约数之上

d=gcd(a,b)
lcm(a,b)=a*d/b

0225-4【PAT B1048】数字加密

#include<cstdio>
#include<cstring>
char dex[15]={'0','1','2','3','4','5','6','7','8','9','J','Q','K'};
void reverse(char s[]){
    int len=strlen(s);
    //反转时不能带=
    for(int i=0;i<len/2;i++){
        int temp=s[i];
        s[i]=s[len-1-i];
        s[len-1-i]=temp;
    }
}
int main(){
    char ans[1100]={0};
    char str1[1100]={0},str2[1100]={0};
    scanf("%s %s",str1,str2);
     reverse(str1);
    reverse(str2);
    int index=0,i;
    for(i=0;i<strlen(str1)&&i<strlen(str2);i++){
        if(i%2==0){
            int an=((str1[i]-'0')+(str2[i]-'0'))%13;
            ans[index]=dex[an];
            index++;     
        }
        else{
            int an=(str2[i]-'0')-(str1[i]-'0');
            if(an<0)
            an+=10;
            ans[index]=an%10+'0';
            index++;
        }
    }
    for(;i<strlen(str1);i++){
    if(i%2==0)
    ans[index]=dex[(str1[i]-'0')%13];
    else
    ans[index]=((str1[i]-'0')*(-1)+10)%10+'0';
    index++;
    }
     for(;i<strlen(str2);i++){
    if(i%2==0)
    ans[index]=dex[(str2[i]-'0')%13];
    else
    ans[index]=(str2[i]-'0')%10+'0';
    index++;
    }
    for(int i=index-1;i>=0;i--)
    printf("%c",ans[i]);
    return 0;
}

【问题分析】

  • 1、首先逆转字符串的操作,要明白他想表达整数,而自己想用字符串表达时要考虑是不是要逆转字符串;
  • 2、逆转字符串的操作,要把控对应的循环是从0—>小于len/2,不然又逆转回去了;
  • 3、要明白具体规则,落单的时候的特殊临界条件的控制是怎样的。

0225-5【PAT B1003】我要通过

#include<cstdio>
#include<cstring>
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        char str[110];
        scanf("%s",str);
        int len=strlen(str);
        //p个数,t个数,其他个数
        int num_p=0,num_t=0,other=0;
        //p位置,t位置
        int loc_p=-1,loc_t=-1;
        //基本统计具体信息
        for(int i=0;i<len;i++){
            if(str[i]=='P'){
                num_p++;
                loc_p=i;
            }else if(str[i]=='T'){
                num_t++;
                loc_t=i;
            }else if(str[i]!='A')
            other++;
        }
        //规则1和规则2不满足排除
        if((num_p!=1)||(num_t!=1)||(other!=0)||(loc_t-loc_p<=1)){
            printf("NO\n");
            continue;
        }
        //规则3不满足排除
        int x=loc_p,y=loc_t-loc_p-1,z=len-loc_t-1;
        if(z-x*(y-1)==x){//将其转换为规则2去判断
            printf("YES\n");
        }else{
             printf("NO\n");
        }
    }
    return 0;
}

【问题分析】

  • 刚开始想这道题的时候觉得要去用递归的方法去求解,因为它建立了三种情况,而它的变化也是按照递归的规则去不断演进的,但是问题就出在了找不到递归的头绪,因为我们拿到的是结果,要从结果往源头去推对应的符合情况
  • 第1个规则很容易解决,第2个原则说白了就是P,T只有1个而前后的一样
  • 第3个原则就是每后面加一倍,中间加1个
  • 此时我们就可以首先用规则1去第一步删除;然后将规则3去用转化为对应的规则,是否能保证前后相等去做,用数学问题解决对应方案的思路是可行且符合常理的。

0225小结

编号内容状态数目
0字符串处理复习PB2
1排序复习PA1
2简单数学复习PB1

总计 PB:4

0226-1【PAT B1008】数组元素循环右移问题

这个问题如果借助额外的数组空间是很方便就能进行对应求解的,但是针对对应的这种要求不循环右移的问题,就会增加其对应的计算难度(但是真正考试的时候是可以不考虑这些的,因为机器检测不出来对应完成的方式是怎样的)
1、难点a:要腾位置,所以要预先推测移动到该位置的是谁,要用逆推的思想解决;
2、难点b:要防止多次重复循环,得到对应的结果,所以要借助最大公倍数和最小公约数的思路解决问题

#include<cstdio>
int gcd(int a,int b){
    if(b==0)return a;
    else return gcd(b,a%b);
}

int main(){
    int a[110];
    //temp临时变量、pos当前位置、next下一个要处理的位置
    int n,m,temp,pos,next;
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    //求出真实m用作对应计算!!!!
    m=m%n;
    if(m!=0){
        //如果m=0,直接输出对应数组即可
        int d=gcd(m,n);
        //通过计算n-m-------n-m+d进行对应pos推算next,进行逐一替换选择,直到推算为自己则保存
        for(int i=n-m;i<n-m+d;i++){
            temp=a[i];
            pos=i;
            do{
                next=(pos-m+n)%n;
                if(next!=i)
                a[pos]=a[next];
                else
                a[pos]=temp;
                pos=next;
            }while(pos!=i);
        }
    }
    //进行逐一输出
    for(int i=0;i<n;i++){
            printf("%d",a[i]);
            if(i<n-1)
            printf(" ");
        }
        return 0;
}

【问题分析】

  • 1、最大公约数的应用于对应的位置求解过程中;
  • 2、要明白怎么简化问题(m--------n%m)
  • 3、怎么去进行推算找到对应的位置,由n-m一直到n-m+1

0226小结

编号内容状态数目
0排序复习PB1
1简单数学复习PB2

1、数字要注意用到浮点数时最好用double类型,保证精度的稳定,防止精度损失
2、排序时要看清是用什么方式进行排序(不低于还是低于)

总计 PB:3

0227-专题【散列】

散列:将元素通过一个函数转换为整数,使得该整数可以唯一的表示这个元素

  • (基本类型)空间换时间的方式:组织成对应的int和bool数组,存在的话设置对应的索引下的值显示和出现即可。
  • 散列函数: 除留余数法、平方取中法、直接定址法;
  • 冲突解决: 线性探查法、平方探查法、链地址法
  • 字符串hash初步:将字符串映射为一个整数
    假设字符串均有大写字母A-Z完成:A-Z转换为0-25;所以最大整数为26len-1
int hashFunc(char S[],int len){
int id=0;
for(int i=0;i<len;i++){
	id=id*26+(S[i]='A');
}
return id;
}

问题:len不能表示太长,如果对应出现了a-z,则应用26-51表示,所以:

int hashFunc(char S[],int len){
int id=0;
for(int i=0;i<len;i++){
	if(S[i]>='A'&&S[i]<='Z'){
	id=id*52+(S[i]-'A');
	}
	if(S[i]>='a'&&S[i]<='z'){
	id=id*52+(S[i]-'a')+26;
	}
}
return id;
}

而如果继续出现数字的话则有两种方法:
①、继续扩大进制,进制数增加到62
②、如果保证末尾是确定个数的数字时,将前面的英文转换为整数,再将末尾的数字直接拼接上去。

int hashFunc(char S[],int len){
	int id=0;
	for(int i=0;i<len-1;i++){
		id=id*26+(S[i]-'A');
	}
	id=id*10+(S[len-1]-'0'); 
}

③、有N个字符串,再给出M个查询字符串,问每个字符串再N个字符串中出现的次数

#include<cstdio>
const int maxn=100;
char S[maxn][5],temp[5];
int hashTable[26*26*26+10]; 
//hash散列确定对应的函数
int hashFunc(char S[],int len){
int id=0;
for(int i=0;i<len;i++){
	id=id*26+(S[i]='A');
}
return id;
}
//主函数进行调度
int main(){
int n,m;
scanf("%d%d",&n,&m);
//hash函数进行对应的转化到对应的hashTable中
for(int i=0;i<n;i++){
	scanf("%s",S[i]);
	int id=hashFunc(S[i],3);
	hashTable[id]++;
}
//进行对应的hashTable中内容的具体查询
for(int i=0;i<m;i++){
	scanf("%s",temp);
	int id=hashFunc(temp,3);
	printf("%d\n",hashTable[id]);
}
return 0;
}

0227-专题【分数的表示与化简】

  • 分数的表示——假分数
    ①、down为非负数,如果分数为负,那么up为负
    ②、如果分数为0,则分子为0,分母为1
    ③、分子和分母没有除了1以外的公约数
struct Fraction{
	int up,down;
}
  • 分数的化简
    ①、如果down为负数,那么分子up和分母down都变成相反数
    ②、如果分子up为0,分母down为1
    ③、约分:求出分子绝对值和分母绝对值的最大公约数d,然后同时除以d
Fraction reduction(Fraction result){
if(result.down<0){
	result.down*=(-1);
	result.up*=(-1);
	}
if(result.up==0)
	result.down=1;
else{
	int d=gcd(abs(result.up),abs(result.down));
	result.up/=d;
	result.down/=d;
}
return result;
}
  • 分数的四则运算
  • ①分数的加法
Fraction add(Fraction f1,Fraction f2){
Fraction result;
result.down=f1.down*f2.down;
result.up=f1.up*f2.down+f2.up*f1.down;
return reduction(result);
}
  • ②分数的减法
Fraction add(Fraction f1,Fraction f2){
Fraction result;
result.down=f1.down*f2.down;
result.up=f1.up*f2.down-f2.up*f1.down;
return reduction(result);
}
  • ③分数的乘法
Fraction add(Fraction f1,Fraction f2){
Fraction result;
result.down=f1.down*f2.down;
result.up=f1.up*f2.up;
return reduction(result);
}
  • ④分数的除法
    除法要额外注意如果题目中读入的除数为0(只需判断f2.up是否为0),那么应该直接特判输出题目要求的输出语句,只有当除数不为0时,才能用该方法;
Fraction add(Fraction f1,Fraction f2){
Fraction result;
result.down=f1.down*f2.up;
result.up=f1.up*f2.down;
return reduction(result);
}

-分数的输出
①、输出前要进行化简;
②、如果分数r的分母down为1,则说明为整数,直接输出分子;
③、如果分子的绝对值大于分母,则说明为假分数,应按带分数的形式输出,即整数部分为r.up/r.down,分子部分采用abs(r.up)%r.down;
④、不满足以上为真分数;

void showResult(Fraction r){
r=reduction(r);
if(r.down==1)
printf("%d",r.up);
else if(abs(r.up)>r.down)
//符号跟随整数部分直接输出,这一部分特别好处理的
printf("%d %d/%d",r.up/r.down,abs(r.up)%r.down,r.down);
else
printf("%d/%d",r.up,r.down);
}

0227小结

编号内容状态数目
0排序复习PB1
1简单数学复习PB2

1、数字要注意用到浮点数时最好用double类型,保证精度的稳定,防止精度损失
2、排序时要看清是用什么方式进行排序(不低于还是低于)

总计 PB:3

0228-专题【素数】

1既不是素数又不是合数,如果一个数只能被自己和1整除,则这个数为素数

  • 问题1:如何判断给定的正整数n是否是质数
    只需要将判断变为由一个1到下线sqrt(n)中即可表示对应的值,从而减少时间复杂度
bool isPrime(int n){
	if(n<=1) return false;
	int sqr=(int)sqrt(1.0*n);
	for(int i=2;i<=sqr;i++){
	if(n%i==0)return false;
	}
	return true;
}
  • 问题2:如何在较短的时间内得到1-n的质数表(基于上面所对应的素数判断标准去求)
const int max=101;
//prime为素数表,pNum为素数个数
int prime[maxn],pNum=0;
bool p[maxn]={0};//p[i]==true表示i为素数
void Find_Prime(){
	for(int i=1;i<maxn;i++){
	if(isPrime(i)==true){
		prime[pNum++]=i;
		p[i]=true;
		}
	}
}

埃式筛法——通过对应筛去过往的数字,如果该数存在不是素数的话,则说明前头肯定出现果对应的因子,所以根据其原理说明剩下的一定是对应的素数

  • 其时间复杂度为O(nloglogn)
const int maxn=101;
int prime[maxn],pNum=0;
bool p[maxn]={0};
void Find_Prime(){
	for(int i=2;i<maxn;i++){
		if(p[i]==false){
		prime[pNum++]=i;
		for(int j=i+i;j<maxn;j+=i){
			p[j]=true;
			}
		}
	}
}

0228-专题【递归】

递归-分治

分解—解决—合并
减治:子问题规模为1
分治:子问题规模大于1

递归-递归
  • 递归核心概念
    ①、递归边界—>递归的尽头
    ②、递归式(递归调用—)—>将原问题变成很多子问题

例子1:n!

int F(int n){
if(n==0)return 1;
else return F(n-1)*n;
}

例子2:Fibonacci数列

int F(int n){
if(n==0)
return 1;
else if(n==1)
return 1;
else
return F(n-1)+F(n-2);
}

例子3:全排列问题这道题的思想很好
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#include<cstdio>
const int maxn=11;
int n,p[maxn],hashTable[maxn]={false};
void generatep(int index){
	if(index==n+1){
		for(int i=1;i<=n;i++){
		printf("%d",p[i]);
		}
		printf("\n");
		return;
	}
	for(int x=1;x<=n;x++){//遍历每一位值
	if(hashTable[x]==false){//如果这一位可以填
		p[index]=x;
		hashTable[x]=true;
		generatep(index+1);
		hashTable[x]=false;
	}
	}
}
int main(){
n=3;
generatep(1);
return 0;
}

例子4:n皇后问题

  • 暴力法解题目,当所有的结果出来之后,比较结果的有效性
int count=0;
void generateP(int index){
	if(index==n+1){
	bool flag=true;
	for(int i=1;i<=n;i++){
		for(int i=1;i<=n;i++){
			if(abs(i-j)==abs(P[i]-P[j])){
				flag=false;
			}
		}
	}
	if(flag==true)count++;
	return;
	}
	for(int x=1;x<=n;x++){
		if(hashTable[x]==false){
		p[index]==x;
		hashTable[x]=false;
		generateP(index+1;
		hashTable[x]=false;
		}
	}
}
  • 回溯法解题目,有些结果在前面已经注定不论后面不论怎么修改其结果也不会改变了
int count=0;
void generateP(int index){
	//对应出口条件
	if(index==n+1){
	count++;
	return;
	}
	//比较该位置的每一个数字的情况
	for(int x=1;x<=n;x++){
		//如果该位数字失效
		if(hashTable[x]==false){
		bool flag=true;
		//遍历之前的数字与该位数字之间的变化是否满足情况,如果不满足则换下一个数字
		for(int pre=1;pre<index;pre++){
			if(abs(index-pre)==abs(x-P[pre])){
				flag=false;
				break;
				}
			}
			//如果满足则继续做该个数字下的情况
			if(flag){
				p[index]==x;
				hashTable[x]=false;
				generateP(index+1;
				hashTable[x]=false;
				}
		}
	}
}

0228-1【PAT B1034】有理数的四则运算

#include<cstdio>
#include<math.h>
// 分数结构体
typedef long long ll;
struct Fraction{
    ll up;
    ll down;
};
// 最大公约数求解
ll gcd(ll a,ll b){
    if(b==0)
        return a;
    else 
        return gcd(b,a%b);
}
// 约分对应过程
Fraction Reduction(Fraction fra){
    if(fra.down<0){
        fra.down*=-1;
        fra.up*=-1;
    }
    if(fra.up==0)
    fra.down=1;
    else{
        int d=gcd(abs(fra.up),fra.down);
        fra.up/=d;
        fra.down/=d;
    }
    return fra;
}
// 相加运算
Fraction add(Fraction fra1,Fraction fra2){
    Fraction result;
    result.down=fra1.down*fra2.down;
    result.up=fra1.up*fra2.down+fra2.up*fra1.down;
    result=Reduction(result);
    return result;
}
// 相减运算
Fraction sub(Fraction fra1,Fraction fra2){
    Fraction result;
    result.down=fra1.down*fra2.down;
    result.up=fra1.up*fra2.down-fra2.up*fra1.down;
    result=Reduction(result);
    return result;
}
// 相乘运算
Fraction mul(Fraction fra1,Fraction fra2){
    Fraction result;
    result.down=fra1.down*fra2.down;
    result.up=fra1.up*fra2.up;
    result=Reduction(result);
    return result;
}
// 相除运算
Fraction chu(Fraction fra1,Fraction fra2){
    Fraction result;
    fra2=Reduction(fra2);
    if(fra2.up==0){
        result.up=1;
        result.down=0;
    }else{
    result.down=fra1.down*fra2.up;
    result.up=fra1.up*fra2.down;
    result=Reduction(result);
    }
    return result;
}
//打印对应分数函数
void printfra(Fraction fra){
    fra=Reduction(fra);
    if(fra.down==1){
    	if(fra.up<0)
        printf("(");
    	printf("%lld",fra.up);
    	if(fra.up<0)
        printf(")");
	}
    
    else if(fra.down==0)
    printf("Inf");
    else if(abs(fra.up)>fra.down){
       ll k=fra.up/fra.down;
        if(k<0)
        printf("(");
        ll kl=(ll)abs(fra.up)%fra.down;
        printf("%lld %lld/%lld",k,kl,fra.down);
        if(k<0)
        printf(")");
    }
    else{
    	if(fra.up<0)
        printf("(");
        printf("%lld/%lld",fra.up,fra.down);
        if(fra.up<0)
        printf(")");
    }
}
// 主函数
int main(){
    Fraction fra1,fra2;
    scanf("%lld/%lld %lld/%lld",&fra1.up,&fra1.down,&fra2.up,&fra2.down);
    fra1=Reduction(fra1);
    fra2=Reduction(fra2);
    printfra(fra1);printf(" + ");printfra(fra2);printf(" = ");printfra(add(fra1,fra2));printf("\n");
    printfra(fra1);printf(" - ");printfra(fra2);printf(" = ");printfra(sub(fra1,fra2));printf("\n");
    printfra(fra1);printf(" * ");printfra(fra2);printf(" = ");printfra(mul(fra1,fra2));printf("\n");
    printfra(fra1);printf(" / ");printfra(fra2);printf(" = ");printfra(chu(fra1,fra2));printf("\n");
    return 0;
}

【问题分析】

  • 1、针对对应的除法要考虑对其分母为0分类;
  • 2、要针对对应的数用long long的形式进行输入和处理,而非简单的int型
  • 3、要明确清楚对应分数的形式,分子操作而分母为非负数这点十分重要

0228小结

编号内容状态数目
0分数的四则运算新学PB1
1素数新学PB2
2散列新学PB1

1、数字要注意用到浮点数时最好用double类型,保证精度的稳定,防止精度损失
2、排序时要看清是用什么方式进行排序(不低于还是低于)

总计 PB:3

汇总

编号内容数目
0查找元素PB 3
1图形编程PB1+C1
2日期处理PB 1
3进制表示PB 2
4字符串PB 7+C1
5简单数学PB4
6排序PA1 PB1
7分数的四则运算PB1
8素数PB2
9散列PB1

总计 PB:23 PA:1 C:2

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值