模拟算法c语言,【算法笔记】-算法模拟(更新中)

题目列表

PAT1001 害死人不偿命的(3n+1)猜想

PAT1032挖掘机技术哪家强

特殊值

PAT1011 A+B 和 C

%I64d 和%lld 的区别

PAT 1016 部分A+B

10^9^

PAT 1026 程序运行时间

"%02d"

PAT 1046 划拳

PAT 1008 数组元素循环右移问题

取值范围,取余特性

PAT 1012 数字分类

".1f"

PAT 1018 锤子剪刀布

字符hash,固定长度循环使用求余,读取字符配合getchar()

PAT 1042 Shuffling Machine

特定数学规律的字符串数组表示

PAT 1046 Shortest Distance

解题思路要更加抽象概括

PAT 1065 A+B and C (64bit)

string 字符串数组 long long int 的相互转换

PAT1001 害死人不偿命的(3n+1)猜想

#include

#include

using namespace std;

int main(){

int n;

scanf("%d",&n);

int cnt=0;

while(n!=1){

if(n%2==0){

n/=2;

}else{

n=(3*n+1)/2;

}

cnt++;

}

printf("%d\n",cnt);

return 0;

}

PAT1032挖掘机技术哪家强

特殊值

分析

算法分析的做法:

先依次读入所有学校的数据,并累加,由于题目给出的是学校编号是连续的,所以从1到N开始遍历最大的值即可

我的做法:

在依次读入学校的数据的时候,就进行最大值的更新,这样的好处在于不需要再从头开始遍历,缺点就是增加了比较的次数

注意

这里面要额外考虑每个学校的分数都为0的情况,由于这里面保证了答案是惟一的,所以在用变量保留当前最大值的时候可以考虑使用新的sum>=sum的情况就进行更新

代码

#include

#include

using namespace std;

const int maxn=100000+5;

int a[maxn];

int main(){

int n;

scanf("%d",&n);

int index,sum=0;

for(int i=0;i

int t1,t2;

scanf("%d%d",&t1,&t2);

a[t1]+=t2;

if(a[t1]>=sum){

sum=a[t1];

index=t1;

}

}

printf("%d %d\n",index,sum);

return 0;

}

PAT1011 A+B 和 C

%I64d 和%lld 的区别

注意

这道题同样只是简单的模拟,int的数据范围是[-231, 231-1],而题目中给出的数据范围是[-231,231],所以在读取A,B,C的时候需要使用long long 这一数据类型

scanf(“lld”,&a);这样进行读取

知识点

%I64d 和%lld 的区别

long long定义方式可以用于gcc/g++,不受平台限制,但不能用于VC6.0。

__int64是Win32平台编译器64位长整型的定义方式,不能用于Linux。

“%lld”用于Linux i386平台编译器,”%I64d”用于Win32平台编译器。

cout只能用于C++编译,在VC6.0中,cout不支持64位长整型。

我现在常用c++,所以使用64位整数时,我使用long long 搭配着%lld

#include

#include

using namespace std;

int main(){

int n;

scanf("%d",&n);

for(int i=0;i

long long a,b,c;

scanf("%lld%lld%lld",&a,&b,&c);

printf("%s%d%s","Case #",i+1,": ");

if(a+b>c) printf("%s","true\n");

else printf("%s","false\n");

}

return 0;

}

PAT 1016 部分A+B

109

主要进行模拟即可(109在int数据的范围内)

#include

#include

using namespace std;

int getnum(int x,int t){

int sum=0;

while(x){

if(x%10==t){

sum=sum*10+t;

}

x/=10;

}

return sum;

}

int main(){

int a,d1,b,d2;

scanf("%d%d%d%d",&a,&d1,&b,&d2);

printf("%d\n",getnum(a,d1)+getnum(b,d2));

return 0;

}

PAT 1026 程序运行时间

“%02d”

这里面正常模拟即可

代码逻辑上没有问题,其实也可以再优化优化

#include

#include

using namespace std;

void printtime(int t){

if(t/10==0) printf("%s","0");

printf("%d",t);

}

int main(){

int t1,t2,time,t=0;

scanf("%d%d",&t1,&t2);

time=t2-t1;

if(time%100>=50) t=1;

time=time/100+t;

int h,m,s;

h=time/3600;

time=time%3600;

m=time/60;

time=time%60;

s=time;

printtime(h);

printf("%s",":");

printtime(m);

printf("%s",":");

printtime(s);

printf("%s","\n");

return 0;

}

算法分析中的参考代码:

97c18d5be5ecbb1eb102ef40929c9371.png我是自己额外单独判断了下是否满两位,不足的数字额外输出0,其实可以直接使用printf的格式控制“%02d”

PAT 1046 划拳

#include

#include

using namespace std;

int main(){

int n,a1,b1,a2,b2,r1=0,r2=0;

scanf("%d",&n);

while(n--){

scanf("%d%d%d%d",&a1,&b1,&a2,&b2);

int sum=a1+a2;

if(b1==sum){

if(b2!=sum){

r2++;

}

}else{

if(b2==sum)

r1++;

}

}

printf("%d %d\n",r1,r2);

return 0;

}

PAT 1008 数组元素循环右移问题

取值范围,取余特性

注意

我在进行实现的时候并没有考虑M有可能是大于N的,所以最开始提交的结果是部分正确。

还有一个规律是当字符串向右移动N位之后其实就是原本的字符串同时为了保证M始终是小于N的,所以令M=M%N。

题目中要求不使用额外的数组空间,其实就利用下标进行运算即可。

算法笔记中: 直接按照题目的含义进行输出结果

我的做法: 利用数学公式来进行计算即可

#include

#include

using namespace std;

const int maxn=100+5;

int a[maxn];

int n,m;

int main(){

scanf("%d%d",&n,&m);

for(int i=0;i

scanf("%d",&a[i]);

}

m=m%n;

for(int i=0;i

printf("%d",a[(i+(n-m))%n]);

if(i!=n-1) printf("%s"," ");

else printf("%s","\n");

}

}

PAT 1012 数字分类

“.1f”

#include

#include

#include

using namespace std;

vector data[5];

bool f[5];

int main(){

int n;

long long sum1=0,max5=-1;

float sum3=0.0;

scanf("%d",&n);

data[0].push_back(0);

while(n--){

long long t;

scanf("%lld",&t);

switch(t%5){

case 0:{

if(t%2==0){

f[0]=true;

data[0][0]+=t;

}

};break;

case 1:{

f[1]=true;

if(data[1].size()%2==0){

data[1].push_back(t);

sum1+=t;

}else{

data[1].push_back(t);

sum1-=t;

}

};break;

case 2:{

f[2]=true;

data[2].push_back(t);

};break;

case 3:{

f[3]=true;

data[3].push_back(t);

sum3+=t;

};break;

case 4:{

f[4]=true;

if(t>max5){

max5=t;

}

};break;

}

}

if(f[0]) printf("%lld ",data[0][0]);

else printf("%s","N ");

if(f[1]) printf("%lld ",sum1);

else printf("%s","N ");

if(f[2]) printf("%lld ",data[2].size());

else printf("%s","N ");

if(f[3]) printf("%.1f ",sum3/data[3].size());

else printf("%s","N ");

if(f[4]) printf("%lld\n",max5);

else printf("%s","N\n");

return 0;

}

PAT 1018 锤子剪刀布

字符hash,固定长度循环使用求余,读取字符配合getchar()

算法笔记思路

a23bcc18950b9743aa902f119e8f9667.png我之前的思路也发现了BCJ,互相克制的巧合性是循环的,但是没有想到可以使用将BCJ 分贝对应0,1,2这样判断的时候,可以利用(K1+1)%3==K2来判断甲赢了乙

#include

#include

using namespace std;

int a[3];

int b[3];

int ac[3];

int bc[3];

int judge(char c1,char c2){

if(c1==c2){

return 0;

}else{

if(c1=='C'&&c2=='J'){

return 1;

}else if(c1=='J'&&c2=='B'){

return 1;

}else if(c1=='B'&&c2=='C'){

return 1;

}

}

return -1;

}

char list[3]={'B','C','J'};

int get_rank(char c1){

if(c1=='B') return 0;

else if(c1=='C') return 1;

else return 2;

}

int main(){

int n;

cin>>n;

char maxa='B',maxb='B';

int ma=0,mb=0;

while(n--){

char c1,c2;

cin>>c1>>c2;

int re=judge(c1,c2);

if(re==1){

a[0]++;

b[2]++;

ac[get_rank(c1)]++;

}else if(re==0){

a[1]++;

b[1]++;

}else{

a[2]++;

b[0]++;

bc[get_rank(c2)]++;

}

}

for(int i=0;i<3;i++){

if(ac[i]>ma)

{

ma=ac[i];

maxa=list[i];

}

if(bc[i]>mb){

mb=bc[i];

maxb=list[i];

}

}

for(int i=0;i<3;i++){

cout<

if(i!=2) cout<

else cout<

}

for(int i=0;i<3;i++){

cout<

if(i!=2) cout<

else cout<

}

cout<

return 0;

}

c2e8385f4fa066266eb33a324f96e84a.png

PAT 1042 Shuffling Machine

特定数学规律的字符串数组表示

40f886ebe43926b34c2d02290210dba2.png在计算x/13的时候,如果没有x-1就会导致,最后一个数值会多1,具体是加一还是减一等调整,可以用特殊边界值来试一试

#include

#include

#include

#include

using namespace std;

int a[55];

int b[55];//存储当前已经经过处理后的数据

int put[55];//每次随机的位置

string data[55]={

"","S1","S2","S3","S4","S5","S6","S7","S8","S9","S10","S11","S12","S13",

"H1","H2","H3","H4","H5","H6","H7","H8","H9","H10","H11","H12","H13",

"C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13",

"D1","D2","D3","D4","D5","D6","D7","D8","D9","D10","D11","D12","D13",

"J1","J2"

};

int main(){

int k;

for(int i=0;i<55;i++){

a[i]=i;

b[i]=i;

put[i]=i;

}

cin>>k;

for(int i=1;i<=54;i++){

cin>>put[i];

}

while(k--){

for(int i=1;i<=54;i++){

a[put[i]]=b[i];

}

swap(b,a);

}

for(int i=1;i<=54;i++){

cout<

if(i!=54) cout<

else cout<

}

return 0;

}

PAT 1046 Shortest Distance

解题思路要更加抽象概括

我的思路

存储从左到右,1到每一个车站的距离,这样便于计算从左到右任意两车站之间的距离

例如:2到4之间的距离为(1,4)-(1,2)

由于整个路程是循环的,所以两个车站之间的距离要么为从左到右的距离,要么为绕了一圈再到该车站的距离,所以最终计算的结果就是这两个结果中的最小值

任意两个车站之间的距离为(x,y) 这里面默认y大于x

Dis1

利用1到两个不同车站之间的距离差计算

Dis1=(1,y)-(1,x)

Dis2

(1,n)-(1,y)+数据给出的最后一个车站到1的距离+(1,x)

Dis2=(y,n)+[n,1]+(1,x)=(1,n)-(1,y)+[n,1]+(1,x)

算法分析的思路

和我的类似,只不过算法分析看的更加抽象,直接将问题抽象看成求解min{dis[left,right],sum-dis[left,right]}

#include

#include

#include

using namespace std;

const int maxn=100000+5;

int oa[maxn];

int dis[maxn];

int main(){

int n,m;

cin>>n;

dis[1]=0;

for(int i=1,t;i<=n;i++){

cin>>t;

oa[i]=t;

dis[i+1]=dis[i]+t;

}

cin>>m;

for(int i=0;i

int t1,t2,re;

cin>>t1;

cin>>t2;

if(t2>t1) swap(t1,t2);

re=min(dis[t1]-dis[t2],dis[n]-dis[t1]+oa[n]+dis[t2]);

cout<

}

return 0;

}

PAT 1065 A+B and C (64bit)

string 字符串数组 long long int 的相互转换

2021/5/13

string 和字符串数组的转化

s1.c_str()

字符串数组和long long int 的转换

#include

x=atoll(chs);

String的相关操作

添加字符在尾部

(1) 常量字符:s1.append(ch);

(2) 变量字符:s1+=ch;

删除字符

s1.erase(pos,n);

即从给定起始位置pos处开始删除, 要删除字符的长度为n

部分正确的代码

最终放弃这个代码了,因为这个代码存在很大的问题,这个代码里面我模拟了一下大数的相加并进行比较,但我这里面相加只是考虑的是两个整数的相加的情形;

之所以想实现这个模拟的原因在于,题目中给出的最大正数的值为263超过了longlong的最大正数的值。由于已经实现了这个功能,所以我想从这个功能出发开始,额外判断一些特殊情况来“填补”我的代码,事实证明垃圾的代码就应该及时止损,一点点补充不是办法。

#include

#include

#include

#include

using namespace std;

int isgt(string s1,string s2,string s3){

string re="";

int a=0;

int i=s1.size()-1,j=s2.size()-1;

while(i>=0&&j>=0){

int x=s1[i]-'0'+s2[j]-'0'+a;

if(x>=10){

a=1;

re+=char('0'+x-10);

// re.append(char('0'+x-10));

}else{

a=0;

re+=char('0'+x);

// re.append(char('0'+x));

}

i--;

j--;

}

while(i>=0){

int x=s1[i]-'0'+a;

if(x>=10){

a=1;

re+=char('0'+x-10);

// re.append(char('0'+x-10));

}else{

a=0;

re+=char('0'+x);

// re.append(char('0'+x));

}

i--;

}

while(j>=0){

int x=s2[j]-'0'+a;

if(x>=10){

a=1;

re+=char('0'+x-10);

// re.append(char('0'+x-10));

}else{

a=0;

re+=char('0'+x);

// re.append(char('0'+x));

}

j--;

}

if(a==1)

re+=char('1');

// re.append(char('1'));

if(re.length()>s3.length()) return 1;

else if(re.length()

else{

reverse(re.begin(),re.end());

for(int k=0;k

if(re[k]>s3[k]){

return 1;

}else if(re[k]

return -1;

}

}

return 0;

}

}

bool judge(string s1,string s2,string s3){

if(s1=="9223372036854775808"&&s2[0]=='-'){

if(s3[0]=='-') return true;

else{

s2.erase(0,1);

return isgt(s2,s3,s1)<0;

}

}

return false;

}

int main(){

int n;

cin>>n;

for(int i=1;i<=n;i++){

long long a,b,c;

string s1,s2,s3;

cin>>s1>>s2>>s3;

string ts1=s1,ts2=s2,ts3=s3;

a=atoll(s1.c_str());

b=atoll(s2.c_str());

c=atoll(s3.c_str());

cout<

if(a+b>c||(s1[0]!='-'&&s2[0]!='-'&&isgt(s1,s2,s3)>0)||judge(ts1,ts2,s3)||judge(s2,s1,s3)){

cout<

}else{

cout<

}

}

return 0;

}

0c0122b85f567a5d839f1abb3f0af3ec.png

分析算法笔记的思路:

可以发现本题的一个难点:除了在于知道计组内部原理会有正溢出和负溢出,还要清楚溢出后的数据范围,计算这个数据范围的时候由于long long有64位,所以在取余数的时候%264。

还要记住263这个数会在计算机表示中变成-263

#include

using namespace std;

int main(){

int n;

cin>>n;

for(int i=1;i<=n;i++){

long long a,b,c,res;

cin>>a>>b>>c;

res=a+b;

bool flag=false;

if(a>0&&b>0&&res<0) flag=true;

else if(a<0&&b<0&&res>=0) flag=false;

else if(res>c) flag=true;

else flag=false;

cout<

if(flag) cout<

else cout<

}

return 0;

}

重新编写的代码还是部分通过,说明最大值真的有263超出了long long范围,需要使用大数模拟

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值