总目录详见https://blog.csdn.net/mrcrack/article/details/84471041
做题原则,找不到测评地址的题不做。2018-11-28
重走长征路---OI每周刷题记录---11月16日 2013
本周共计13题
测评地址:
队列
1.卡牌游戏
模拟
2.最大公约数和最小公倍数问题 //在线测评地址https://www.luogu.org/problemnew/show/P1029
3.回文质数
4.苹果摘淘淘 //在线测评地址https://www.luogu.org/problemnew/show/P1046
背包dp
5.金明的预算方案 //在线测评地址https://www.luogu.org/problemnew/show/P1064
高精度
6.hanoi双塔
dp
7.打水漂
bfs
8.魔兽世界
9.紧急救援 //在线测评地址http://www.rqnoj.cn/problem/34
10.24点 //在线测评地址http://www.rqnoj.cn/problem/74
思考题
11.兔子的世界 找不到OJ
模拟
12.兔子列队 找不到OJ
13.兔羊大战 找不到OJ
题解:
队列
1.卡牌游戏
模拟
2.最大公约数和最小公倍数问题
//P1029 最大公约数和最小公倍数问题
//在线测评地址https://www.luogu.org/problemnew/show/P1029
//研究样例,发现规律
//60/3=20
//1*20 3=>3 60 gcd(1,20)=1
//2*10 3=>6 30 gcd(2,10)=2 舍弃
//4*5 3=>12 15 gcd(4,5)=1
//5*4 3=>15 12 gcd(5,4)=1
//10*2 3=>30 6 gcd(30,6)=6 舍弃
//20*1 3=>60 3 gcd(20,1)=1
//还需欧几里得定理
//纯模拟,发现规律
//在担心,统计个数,是否int会溢出,编好后,测试一下
//编好代码后,发现1000000的因数对最多1000000,故int不会溢出
//样例通过,提交80分,测试点4WA,
//在考虑,有可能出现个数为0的情况,即y%x!=0,需特判
//加上特判,提交AC。2019-1-18 21:54
//本次编写,全过程,无任何参考,完全是独立思考的结果。
#include <stdio.h>
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int i,x,y,cnt=0;
scanf("%d%d",&x,&y);
if(y%x!=0){//有可能出现个数为0的情况,即y%x!=0,需特判
printf("0\n");
return 0;
}
y/=x;
for(i=1;i<=y;i++)
if(y%i==0&&gcd(i,y/i)==1)//此处写成 if(y%i==0&&gcd(i,y%i)==1) 确实有点昏
cnt++;
printf("%d\n",cnt);
return 0;
}
3.回文质数
4.苹果摘淘淘
//P1046 陶陶摘苹果
//NOIP 2005 普及组 第1题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1046
//简单的模拟
//样例通过,提交AC。2019-1-24 21:29
#include <stdio.h>
int h[15];
int main(){
int i,b,cnt=0;
for(i=1;i<=10;i++)scanf("%d",&h[i]);
scanf("%d",&b);
b+=30;
for(i=1;i<=10;i++)
if(h[i]<=b)cnt++;
printf("%d\n",cnt);
return 0;
}
背包dp
5.金明的预算方案
//P1064 金明的预算方案
//NOIP 2006 提高组 第2题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1064
//每件物品的价格(都是1010元的整数倍),算钱时,可以先除以10,最后总结果,再乘以10
//可以大大减小运算时间
//因f[10100][3210],10100*3210*4/1024/1024=124M,比较险,内存容易溢出
//决定还是采用降维的方式,采用一维数组。
//基本思路,选完主件,马上选对应的附件
//每个主件可以有0个、1个或2个附件,有个疑问,每个附件可用0,1,2次吗?
//结合题意看,应该是0或1次。主件可以有0个,1个,或2个不同附件。
//开二维数组q[i][0]表示附件的个数,q[i][1]=j附件1在位置j,q[i][2]=k附件2在位置k
//q[i][0]=-1表示附件,为自己的奇思妙想感到高兴。
//01背包
//样例通过,提交40分,测试点3,4,7-10WA。2019-1-13 19:46
//以下为40分代码
//准备考虑,主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行讨论
//修改,提交30分,发现更糟糕,测试点3-8,10WA。2019-1-13 21:16
//感觉是有问题的。以下为30分代码。
//想看答案,忍住了,心想,要是接下来的思路还有重大问题,再看解答。
//仔细想想,应该同时对 主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行选择
//大篇幅修改,提交AC.那个高兴啊,没有参考任何资料,一点一点的磨出,思维达到新高度。2019-1-14 8:19
//以下为AC代码。
#include <stdio.h>
#include <string.h>
int f[3210],v[65],p[65],q[65][4];
int max(int a,int b){
return a>b?a:b;
}
int main(){
int n,m,i,j,d;
memset(f,0,sizeof(f));
memset(q,0,sizeof(q));
scanf("%d%d",&n,&m);
n/=10;
for(i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&p[i],&d);
v[i]/=10;//漏了此句
if(d>0){
q[i][0]=-1;//标记附件
q[d][++q[d][0]]=i;//关联主附件位置
}
}
for(i=1;i<=m;i++)
if(q[i][0]>=0)//主件
for(j=n;j>=v[i];j--){//在同一处话费,对 主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行选择
f[j]=max(f[j],f[j-v[i]]+v[i]*p[i]);
if(q[i][0]>=1&&j>=v[i]+v[q[i][1]])f[j]=max(f[j],f[j-v[i]-v[q[i][1]]]+v[i]*p[i]+v[q[i][1]]*p[q[i][1]]);
if(q[i][0]==2){
if(j>=v[i]+v[q[i][2]])
f[j]=max(f[j],f[j-v[i]-v[q[i][2]]]+v[i]*p[i]+v[q[i][2]]*p[q[i][2]]);
if(j>=v[i]+v[q[i][1]]+v[q[i][2]])
f[j]=max(f[j],f[j-v[i]-v[q[i][1]]-v[q[i][2]]]+v[i]*p[i]+v[q[i][1]]*p[q[i][1]]+v[q[i][2]]*p[q[i][2]]);
}
}
printf("%d\n",f[n]*10);
return 0;
}
//P1064 金明的预算方案
//NOIP 2006 提高组 第2题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1064
//每件物品的价格(都是1010元的整数倍),算钱时,可以先除以10,最后总结果,再乘以10
//可以大大减小运算时间
//因f[10100][3210],10100*3210*4/1024/1024=124M,比较险,内存容易溢出
//决定还是采用降维的方式,采用一维数组。
//基本思路,选完主件,马上选对应的附件
//每个主件可以有0个、1个或2个附件,有个疑问,每个附件可用0,1,2次吗?
//结合题意看,应该是0或1次。主件可以有0个,1个,或2个不同附件。
//开二维数组q[i][0]表示附件的个数,q[i][1]=j附件1在位置j,q[i][2]=k附件2在位置k
//q[i][0]=-1表示附件,为自己的奇思妙想感到高兴。
//01背包
//样例通过,提交40分,测试点3,4,7-10WA。2019-1-13 19:46
//以下为40分代码
//准备考虑,主件,主件+附件1,主件+附件2,主件+附件1+附件2 进行讨论
//修改,提交30分,发现更糟糕,测试点3-8,10WA。2019-1-13 21:16
//感觉是有问题的。以下为30分代码。
#include <stdio.h>
#include <string.h>
int f[3210],v[65],p[65],q[65][4];
int main(){
int n,m,i,j,k,d,V,P;
memset(f,0,sizeof(f));
memset(q,0,sizeof(q));
scanf("%d%d",&n,&m);
n/=10;
for(i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&p[i],&d);
v[i]/=10;//漏了此句
if(d>0){
q[i][0]=-1;//标记附件
q[d][++q[d][0]]=i;//关联主附件位置
}
}
for(i=1;i<=m;i++)
if(q[i][0]>=0){//主件
V=v[i],P=v[i]*p[i];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
if(q[i][0]>=1){
V+=v[q[i][1]],P+=v[q[i][1]]*p[q[i][1]];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
}
if(q[i][0]==2){
V=v[i]+v[q[i][2]],P=v[i]*p[i]+v[q[i][2]]*p[q[i][2]];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
V=v[i]+v[q[i][1]]+v[q[i][2]],P=v[i]*p[i]+v[q[i][1]]*p[q[i][1]]+v[q[i][2]]*p[q[i][2]];
}
}
printf("%d\n",f[n]*10);
return 0;
}
//P1064 金明的预算方案
//NOIP 2006 提高组 第2题 共4题
//在线测评地址https://www.luogu.org/problemnew/show/P1064
//每件物品的价格(都是1010元的整数倍),算钱时,可以先除以10,最后总结果,再乘以10
//可以大大减小运算时间
//因f[10100][3210],10100*3210*4/1024/1024=124M,比较险,内存容易溢出
//决定还是采用降维的方式,采用一维数组。
//基本思路,选完主件,马上选对应的附件
//每个主件可以有0个、1个或2个附件,有个疑问,每个附件可用0,1,2次吗?
//结合题意看,应该是0或1次。主件可以有0个,1个,或2个不同附件。
//开二维数组q[i][0]表示附件的个数,q[i][1]=j附件1在位置j,q[i][2]=k附件2在位置k
//q[i][0]=-1表示附件,为自己的奇思妙想感到高兴。
//01背包
//样例通过,提交40分,测试点3,4,7-10WA。2019-1-13 19:46
//以下为40分代码
#include <stdio.h>
#include <string.h>
int f[3210],v[65],p[65],q[65][4];
int main(){
int n,m,i,j,k,d,V,P;
memset(f,0,sizeof(f));
memset(q,0,sizeof(q));
scanf("%d%d",&n,&m);
n/=10;
for(i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&p[i],&d);
v[i]/=10;//漏了此句
if(d>0){
q[i][0]=-1;//标记附件
q[d][++q[d][0]]=i;//关联主附件位置
}
}
for(i=1;i<=m;i++)
if(q[i][0]>=0){//主件
for(k=0;k<=q[i][0];k++){
if(k==0)V=v[i],P=v[i]*p[i];
else V+=v[q[i][k]],P+=v[q[i][k]]*p[q[i][k]];
for(j=n;j>=V;j--)
if(f[j]<f[j-V]+P)
f[j]=f[j-V]+P;
}
}
printf("%d\n",f[n]*10);
return 0;
}
高精度
6.hanoi双塔
dp
7.打水漂
bfs
8.魔兽世界
9.紧急救援
//PID34 / 紧急援救
//在线测评地址http://www.rqnoj.cn/problem/34
//用户名:mrwalking
//研究所算0步,还是1步,程序编好后,就知道了
//采用广搜BFS算法
//测试样例,没有输出,多次阅读程序,没有问题
//问题出在哪呢,再次读题,发现第1行,第1列
//代码中是第0行,第0列,马上进行修改
//样例通过,发现, 研究所算0步
//提交AC。2019-2-3 08:51
#include <stdio.h>
#include <string.h>
#define maxn 1010
int n;
int next[][2]={{-1,0},{1,0},{0,-1},{0,1}};//上下左右
char map[maxn][maxn],vis[maxn][maxn];
struct node{
int r,c,s;//s表示步数
}q[maxn*maxn];
void bfs(int sr,int sc,int er,int ec){
int h,t,r,c,s,k,nr,nc,ns;
memset(vis,0,sizeof(vis));
h=t=1,q[t].r=sr,q[t].c=sc,q[t].s=0,vis[sr][sc]=1,t++;//此处写成 vis[r][c]=1
while(h<t){
r=q[h].r,c=q[h].c,s=q[h].s;
if(r==er&&c==ec){
printf("%d\n",s);
break;
}
for(k=0;k<4;k++){
nr=r+next[k][0],nc=c+next[k][1],ns=s+1;
if(0<=nr&&nr<n&&0<=nc&&nc<n&&vis[nr][nc]==0&&map[nr][nc]=='0')
q[t].r=nr,q[t].c=nc,q[t].s=ns,vis[nr][nc]=1,t++;//此处写成 q[t].r=nr,q[t],c=nc,q[t].s=ns,vis[nr][nc]=1,t++;
}
h++;
}
}
int main(){
int sr,sc,er,ec,i;
scanf("%d",&n);
for(i=0;i<n;i++)scanf("%s",map[i]);
scanf("%d%d%d%d",&sr,&sc,&er,&ec);
sr-=1,sc-=1,er-=1,ec-=1;//添加此行,用了6分钟
bfs(sr,sc,er,ec);
return 0;
}
10.24点
//PID74 / 24点
//在线测评地址http://www.rqnoj.cn/problem/74
//用户名:mrwalking
//没玩过扑克的,这个题目可能会读不懂
//题目,来自生活,需有生活经验
//粗粗一想,没有头绪,静下心来,有了思路
//4个数的排列数有4*3*2*1=24种
//每种,数和数之间有 加减乘除 4中情况,每种有4个数
//需填3次符号,故每种的计算情况有4*4*4=64
//总的计算次数24*64=1536不超时,在算的过程中,发现24点,即可退出
//该题思路 深搜dfs+回溯。
//C中 读取字符串 比 字符容易,采用曲线救国的方式。
//该题要小心,读取的数据有可能是10,字符串的读取方式,有2位
//写代码的过程中,笔误很难避免,最好的办法,编好一个功能,马上进行测试。
//样例通过,提交WA40分,测试点2,5,7-10WA。2019-2-3 10:16
//以下为40分代码。
//要是能看到WA的测试数据就好了。
//看了讨论,说是1,可能是给出A,可能是直接给出1
//if('1'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';//此处写成if('2'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';
//修改,提交WA50分,测试点2,7-10WA。该题是有些赖皮,1可来自A,也可来自1. 2019-2-3 10:35
//该题,还有一点没说明,除不尽,怎么处理,之前解法是,除不尽,就不除
//看了https://www.cnblogs.com/Emine/p/7674544.html发现,除不尽,继续除
//总归来说,该题有些情况没说清楚,从读者读题会有多种的理解角度来看,题出得不好。
//case '/':dfs_compute(step+1,ans/b[step]);break;//此处写成 case '/':if(ans%b[step]==0)dfs_compute(step+1,ans/b[step]);break;题意不清,造成的。
//修改,提交WA60分,测试点2,8-10WA。2019-2-3 10:50
//翻看http://hzwer.com/224.html例子
//比如3, 3, 8, 8的24点答案:
//1: 8 ÷ (3 – 8 ÷ 3)
//2: 8 ÷ (3 – (8 ÷ 3))
//以下是60分代码,2019-2-3 11:02
//代码进行大改,
//if(a[i])dfs(step+1,ans/a[i]);//此处写成 dfs(step,ans/a[i]);昏倒 查了40分钟
//if(!(-0.00001<=ans&&ans<=0.00001))dfs(step+1,a[i]/ans);//此处写成dfs(step,a[i]/ans);昏倒 查了40分钟
//2处笔误,查了40分钟
//例子3 3 8 8 yes通过,提交AC.2019-2-3 12:46
//一定的奥数训练,还是需要的。
#include <stdio.h>
#include <string.h>
int a[8],vis[8],flag=0;
char s[8][8];
void dfs(int step,double ans){
int i;
if(step==4){
if(23.99999<=ans&&ans<=24.00001)flag=1;
return;
}
for(i=1;i<=4;i++)
if(vis[i]==0){
vis[i]=1;
dfs(step+1,ans+a[i]);
dfs(step+1,ans-a[i]);
dfs(step+1,a[i]-ans);//漏了此种情况
dfs(step+1,ans*a[i]);
if(a[i])dfs(step+1,ans/a[i]);//此处写成 dfs(step,ans/a[i]);昏倒 查了40分钟//漏了判断分母是否为0
if(!(-0.00001<=ans&&ans<=0.00001))dfs(step+1,a[i]/ans);//此处写成dfs(step,a[i]/ans);昏倒 查了40分钟//此处写成if(ans)dfs(step,a[i]/ans);浮点数比较大小,要特别小心//漏了此种情况
vis[i]=0;
}
}
int main(){
int i;
for(i=1;i<=4;i++){
scanf("%s",s[i]);
if('1'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';//此处写成if('2'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';//此处写成 if('2'<=s[i][0]&&s[i][0]<=9)a[i]=s[i][0]-'0';
else if(s[i][0]=='1'&&s[i][1]=='0')a[i]=10;//此处写成 else if(s[i][0]=='1'&&s[i][1]='0')a[i]=10;
else{
switch(s[i][0]){
case 'A':a[i]=1;
break;
case 'J':a[i]=11;
break;
case 'Q':a[i]=12;
break;
case 'K':a[i]=13;
}
}
}
memset(vis,0,sizeof(vis));
for(i=1;i<=4;i++){
vis[i]=1;
dfs(1,a[i]);
vis[i]=0;
}
if(flag==1)printf("yes\n");
else printf("no\n");
return 0;
}
//PID74 / 24点
//在线测评地址http://www.rqnoj.cn/problem/74
//用户名:mrwalking
//没玩过扑克的,这个题目可能会读不懂
//题目,来自生活,需有生活经验
//粗粗一想,没有头绪,静下心来,有了思路
//4个数的排列数有4*3*2*1=24种
//每种,数和数之间有 加减乘除 4中情况,每种有4个数
//需填3次符号,故每种的计算情况有4*4*4=64
//总的计算次数24*64=1536不超时,在算的过程中,发现24点,即可退出
//该题思路 深搜dfs+回溯。
//C中 读取字符串 比 字符容易,采用曲线救国的方式。
//该题要小心,读取的数据有可能是10,字符串的读取方式,有2位
//写代码的过程中,笔误很难避免,最好的办法,编好一个功能,马上进行测试。
//样例通过,提交WA40分,测试点2,5,7-10WA。2019-2-3 10:16
//以下为40分代码。
//要是能看到WA的测试数据就好了。
//看了讨论,说是1,可能是给出A,可能是直接给出1
//if('1'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';//此处写成if('2'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';
//修改,提交WA50分,测试点2,7-10WA。该题是有些赖皮,1可来自A,也可来自1. 2019-2-3 10:35
//该题,还有一点没说明,除不尽,怎么处理,之前解法是,除不尽,就不除
//看了https://www.cnblogs.com/Emine/p/7674544.html发现,除不尽,继续除
//总归来说,该题有些情况没说清楚,从读者读题会有多种的理解角度来看,题出得不好。
//case '/':dfs_compute(step+1,ans/b[step]);break;//此处写成 case '/':if(ans%b[step]==0)dfs_compute(step+1,ans/b[step]);break;题意不清,造成的。
//修改,提交WA60分,测试点2,8-10WA。2019-2-3 10:50
//翻看http://hzwer.com/224.html例子
//比如3, 3, 8, 8的24点答案:
//1: 8 ÷ (3 – 8 ÷ 3)
//2: 8 ÷ (3 – (8 ÷ 3))
//以下是60分代码,2019-2-3 11:02
#include <stdio.h>
#include <string.h>
int a[8],b[8],vis[8],flag=0;
char s[8][8],sign[8]="+-*/";
void dfs_compute(int step,double ans){
int i;
if(step==3+1){
if(23.99999<=ans&&ans<=24.00001)flag=1;
return;
}
for(i=0;i<4;i++){
switch(sign[i]){
case '+':dfs_compute(step+1,ans+b[step]);break;
case '-':dfs_compute(step+1,ans-b[step]);break;
case '*':dfs_compute(step+1,ans*b[step]);break;
case '/':dfs_compute(step+1,ans/b[step]);break;//此处写成 case '/':if(ans%b[step]==0)dfs_compute(step+1,ans/b[step]);break;题意不清,造成的。
}
}
}
void dfs(int step){
int i,j;
if(step==4+1){
dfs_compute(1,b[1]);
return;
}
for(i=1;i<=4;i++)
if(vis[i]==0){
vis[i]=1;
b[step]=a[i];
dfs(step+1);
vis[i]=0;
}
}
int main(){
int i;
for(i=1;i<=4;i++){
scanf("%s",s[i]);
if('1'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';//此处写成if('2'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';//此处写成 if('2'<=s[i][0]&&s[i][0]<=9)a[i]=s[i][0]-'0';
else if(s[i][0]=='1'&&s[i][1]=='0')a[i]=10;//此处写成 else if(s[i][0]=='1'&&s[i][1]='0')a[i]=10;
else{
switch(s[i][0]){
case 'A':a[i]=1;
break;
case 'J':a[i]=11;
break;
case 'Q':a[i]=12;
break;
case 'K':a[i]=13;
}
}
}
memset(vis,0,sizeof(vis));
dfs(1);
if(flag==1)printf("yes\n");
else printf("no\n");
return 0;
}
//PID74 / 24点
//在线测评地址http://www.rqnoj.cn/problem/74
//用户名:mrwalking
//没玩过扑克的,这个题目可能会读不懂
//题目,来自生活,需有生活经验
//粗粗一想,没有头绪,静下心来,有了思路
//4个数的排列数有4*3*2*1=24种
//每种,数和数之间有 加减乘除 4中情况,每种有4个数
//需填3次符号,故每种的计算情况有4*4*4=64
//总的计算次数24*64=1536不超时,在算的过程中,发现24点,即可退出
//该题思路 深搜dfs+回溯。
//C中 读取字符串 比 字符容易,采用曲线救国的方式。
//该题要小心,读取的数据有可能是10,字符串的读取方式,有2位
//写代码的过程中,笔误很难避免,最好的办法,编好一个功能,马上进行测试。
//样例通过,提交WA40分,测试点2,5,7-10WA。2019-2-3 10:16
//以下为40分代码。
#include <stdio.h>
#include <string.h>
int a[8],b[8],vis[8],flag=0;
char s[8][8],sign[8]="+-*/";
void dfs_compute(int step,int ans){
int i;
if(step==3+1){
if(ans==24)flag=1;
return;
}
for(i=0;i<4;i++){
switch(sign[i]){
case '+':dfs_compute(step+1,ans+b[step]);break;
case '-':dfs_compute(step+1,ans-b[step]);break;
case '*':dfs_compute(step+1,ans*b[step]);break;
case '/':if(ans%b[step]==0)dfs_compute(step+1,ans/b[step]);break;
}
}
}
void dfs(int step){
int i,j;
if(step==4+1){
dfs_compute(1,b[1]);
return;
}
for(i=1;i<=4;i++)
if(vis[i]==0){
vis[i]=1;
b[step]=a[i];
dfs(step+1);
vis[i]=0;
}
}
int main(){
int i;
for(i=1;i<=4;i++){
scanf("%s",s[i]);
if('2'<=s[i][0]&&s[i][0]<='9')a[i]=s[i][0]-'0';//此处写成 if('2'<=s[i][0]&&s[i][0]<=9)a[i]=s[i][0]-'0';
else if(s[i][0]=='1'&&s[i][1]=='0')a[i]=10;//此处写成 else if(s[i][0]=='1'&&s[i][1]='0')a[i]=10;
else{
switch(s[i][0]){
case 'A':a[i]=1;
break;
case 'J':a[i]=11;
break;
case 'Q':a[i]=12;
break;
case 'K':a[i]=13;
}
}
}
memset(vis,0,sizeof(vis));
dfs(1);
if(flag==1)printf("yes\n");
else printf("no\n");
return 0;
}
思考题
11.兔子的世界
模拟
12.兔子列队
13.兔羊大战