目录
算法学习
1.水坑
输入输出样例
输入 #1复制
10 12 W........WW. .WWW.....WWW ....WW...WW. .........WW. .........W.. ..W......W.. .W.W.....WW. W.W.W.....W. .W.W......W. ..W.......W.输出 #1复制
3
1.dfs参量:x,y(二维数组);
2.for循环:8个方向的选择;
3.剪枝干:标记+障碍+边界;
4.终止条件:无设置,遇到不是连通块自动停止搜索,if 剪枝干即为终止条件;
5.注意:字符输入getchar();连通块四周均为w的为一个水坑;
#include<stdio.h> char a[200][200]; int ans=0,book[200][200],n,m; void dfs(int x,int y) { book[x][y]=1; //标记 int tx,ty; int bx[]= {-1,1,0,0,1,-1,-1,1}; //8个方向,九宫格; int by[]= {0,0,1,-1,1,-1,1,-1}; for(int i=0; i<8; i++) { tx=x+bx[i]; ty=y+by[i]; if(tx<1||ty<1||tx>n||ty>m)continue; //跳过边界 if(a[tx][ty]=='W'&&book[tx][ty]==0) //未标记和目标量 { dfs(tx,ty); //搜索九宫格下一个方向; } } return ; } int main() { scanf("%d %d",&n,&m); getchar(); //前后scanf,getchar吸收回车 for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { scanf("%c",&a[i][j]); } getchar(); //前后scanf,getchar吸收回车 } for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(a[i][j]=='W'&&book[i][j]==0)//遇到w且没有被标记 { dfs(i,j); //搜索九宫格附近w ans++; //水坑+1 } } } printf("%d",ans); }
2.Perket
Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 nn 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 ss 和苦度 bb。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
输入格式
第一行一个整数 nn,表示可供选用的食材种类数。
接下来 nn 行,每行 22 个整数 s_isi 和 b_ibi,表示第 ii 种食材的酸度和苦度。
输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
输入输出样例
输入 #1复制
1 3 10输出 #1复制
7
1.dfs参量设置:x,y分别为酸甜度数总和,step;
2.for设置:n种调料;
3.终止条件:step==n+1调料加完,在出口设置对所有组找最小值;
4.注意:回溯时标记和值均要还原;
#include<stdio.h> #include<math.h> int n,a[100],b[100]; int book[100],minn=1000000; int min(int a,int b) //找最小值min函数; { return a<b?a:b; } void dfs(int x,int y,int step) //n种食材,1种食材分别有x甜度调料,y苦度调料两种调料; { if(step==n+1) //每种食材至少加1个调料,n种食材==n步steps; { minn=min(abs(x-y),minn); //abs绝对值函数; return ; } for(int i=1;i<=n;i++) { if(book[i]==0) { x*=a[i]; y+=b[i]; //计算甜度和苦度; book[i]=1; //标记; dfs(x,y,step+1); //进入下一层 book[i]=0; //取消标记; x/=a[i]; //全部还原现场,别漏; y-=b[i]; } } return ; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d %d",&a[i],&b[i]); } dfs(1,0,1); //×从1开始,+从0开始,层数从1开始; printf("%d",minn); //全局变量minn,值在函数中改变; }
3.皇后问题
P1219 [USACO1.5]八皇后 Checker Challenge - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
1.解题关键:横竖斜只有1个皇后;斜:横纵坐标之和,横纵坐标之差
2.dfs参数设置:step,不用调用每层x,y,不是迷宫探险类,只用check二维数组上每一点
3.for循环设置:check,n层每层皇后是否满足check;
4.终止条件:step==n+1;
#include<stdio.h> int n,a[20]; //i表示行,a[i]表示列; int cnt=0; int check(int x,int y) //n皇后是否成立,check游戏标准:横竖斜仅有一个皇后; { for(int i=1; i<=x; i++) //无需讨论行==情况,每次放step都是一行一行放的 { if(a[i]==y)return 0; //皇后位置和其他皇后列==(×) if(i+a[i]==x+y)return 0; //皇后位置和其他皇后对角线1(×) if(i-a[i]==x-y)return 0; //皇后位置和其他皇后对角线2(×) } return 1; } void dfs(int step) //表示第step个皇后放在何处 { if(step==n+1) //dfs最后一层为输出 { cnt++; //解的个数 if(cnt<=3) { for(int i=1; i<=n; i++) { printf("%d ",a[i]); if(i%n==0)printf("\n"); } } return ; } for(int j=1; j<=n; j++) //共1-8列 { if(check(step,j)) //check第step行的皇后是否能放在j列上 { a[step]=j; //放在j列,标记; dfs(step+1); //进入下一层,放下一个皇后; a[step]=0; //取消标记 } } } int main() { scanf("%d",&n); dfs(1); //第一层开始 printf("%d",cnt); return 0; }
刷题网站
1.奖学金
问题 E: 谁拿了最多奖学金(JSU-ZJJ) - OJ (jsuacm.cn)http://jsuacm.cn/problem.php?cid=1684&pid=4
#include <stdio.h> struct student { char name[20]; //姓名 int aveScore; //期末平均成绩 int classScore; //班级议论成绩 char leader; //是否是学生干部 char west; //是否是西部学生 int articles; //论文次数 }; int main() { int n; while(~scanf("%d",&n)) { getchar(); int sum=0;//奖金总数 int max=0,k=0,i=0;//记录最多奖金数 struct student stu[200]; for(i=0; i<n; i++) { scanf("%s %d %d %c %c %d",stu[i].name,&stu[i].aveScore,&stu[i].classScore,&stu[i].leader,&stu[i].west,&stu[i].articles); //getchar(); } for(i=0; i<n; i++) { int jiangjin=0; if(stu[i].aveScore>80 && stu[i].articles>=1) jiangjin+=8000; if(stu[i].aveScore>85 && stu[i].classScore>80) jiangjin+=4000; if(stu[i].aveScore>90) jiangjin+=2000; if(stu[i].aveScore>85 && stu[i].west == 'Y') jiangjin+=1000; if(stu[i].classScore>80 && stu[i].leader=='Y') jiangjin+=850; sum+=jiangjin; if(jiangjin>max) { max=jiangjin; k=i;//当前序号 } } printf("%s\n%d\n%d\n",stu[k].name,max,sum); } return 0; }
2.乒乓球
问题 F: 乒乓球 - OJ (jsuacm.cn)http://jsuacm.cn/problem.php?cid=1684&pid=5 字符串输入转为利用多组输入字符,遇到'E'则跳出输出循环
#include <stdio.h> #include <string.h> int main() { int a=0, b=0, len,t=0,i; char ans[65000],s; while(~scanf("%c",&s)) //多组输入 { if(s=='E')break; ans[t++]=s; } len = strlen(ans); for (i = 0; i < len; i++) //11分制 { if (ans[i] == 'W') a++; else if (ans[i] == 'L') b++; if ((a >= 11 && a - b >= 2 )||(b >= 11 && b - a >= 2) ) { printf("%d:%d\n", a, b); a = 0, b = 0; //重置 } } printf("%d:%d\n", a, b);//输出没有打完的时候的比分 puts(""); a = 0, b = 0; //初始化 for (i = 0; i < len ; i++) //21分制 { if (ans[i] == 'W') a++; else if (ans[i] == 'L') b++; if ((a >= 21 && a - b >= 2)||(b >= 21 && b - a >= 2) ) { printf("%d:%d\n", a, b); a = 0, b = 0; //重置 } } printf("%d:%d", a, b);//输出没有打完的时候的比分,还没有打则会输出0:0 }
3.串的处理
问题 I: 串的处理 - OJ (jsuacm.cn)http://jsuacm.cn/problem.php?cid=1684&pid=8
#include <stdio.h> #include <string.h> int main() { char ch[201]; while(gets(ch)!=NULL) { int len=strlen(ch); int c[201]= {0},d[201]= {0}; if(ch[0]>='a'&&ch[0]<='z') ch[0]-=32; //转化为大写,字符直接运算 for(int i=1; i<len; i++) { if(ch[i]<='z'&&ch[i]>='a'&&ch[i-1]==' ') //分类讨论 { ch[i]-=32; } if(ch[i]==' '&&ch[i-1]==' ') //空格重复出现的时候 { d[i]=1; //桶标记位置,只标记了一个 } if(ch[i]<='z'&&ch[i]>='a'&&ch[i-1]<='9'&&ch[i-1]>='0') { c[i]=1; //桶标记位置 } if(ch[i]<='9'&&ch[i]>='0'&&((ch[i-1]<='z'&&ch[i-1]>='a')||(ch[i-1]<='Z'&&ch[i-1]>='A'))) { c[i]=1; //桶标记位置 } for(int i=0; i<len; i++) { if(c[i]==1)printf("_"); //输出标记点的特殊指令 if(d[i]==1)continue; //区别桶1桶2执行不同指令 } printf("\n"); } } }