几道周赛题目(bfs,dfs,kmp,快速幂运算,并查集)
2015-08-08 18:05
246 查看
1691: 找规律(二分快速求幂)
时间限制: 1 Sec 内存限制: 128 MB题目描述
给出四个数,前三个是某个数列的前三项,这个数列只可能是等差或者等比数列,然后让你求出某一项(每一项给出的第四个数),对200907取余的结果。输入
输入包含多组测试数据,每组测试数据包含4个整数,前三个整数是数列的前三项,最后一个数是n,四个数的范围都是1~10^9输出
输出这个数列的第n项%200907样例输入
1 2 3 5 1 2 4 5
样例输出
5 16
这个题用的求余运算和快速幂取模运算,这两个自己都会,但是卡在了一个最不应该的细节上,没注意数的范围,没使用长整形变量,否则这个题也是很容易就解决了,不想再说自己什么了,有时候就是冷静不足,不知道造成了多少失误,今天算是给自己个教训吧,以后多长个心眼,多想想,别一见到题就a,也不检查就提交,只能自作自受。
#include<cstdio> int main() { int a,b,c,n;long long d,q,s; while(~scanf("%d%d%d%d",&a,&b,&c,&n)) { if(a+c==2*b) { d=b-a; s=(((n-1)%200907)*(d%200907)+a)%200907;//同余定理自己还是不够熟练,需要再理解理解 } else { q=b/a;--n;s=a; while(n>=1)//二分法快速幂运算 { q%=200907; if(n&1) { s*=q; s%=200907; --n; } if(n) { q*=q; n>>=1; } } } printf("%lld\n",s); } return 0; }
1689: 迷宫寻宝(bfs搜索)
时间限制: 1 Sec 内存限制: 128 MB
题目描述
迷宫寻宝。已知:若某人在位置(x, y),他下一次只能移动到(x-1, y)、(x+1, y)、(x, y-1)、(x, y+1)四个位置中的任一个(前提不能越界)。要求移动一步需要1分钟。请你帮他算出找到宝物所需要花费的最少时间。
迷宫是一个N*M的地图,图中只有四个数字。
0:空地,可以走
1:有障碍,不可以走
2:起点
3:宝物位置(只有一个宝物)
题目保证至少有一条路可以到达宝物位置。
输入
输入数据有多组。
每组以两个整数N和M开始,分别表示迷宫的行数和列数,接下来N行每行有M个数。(1 <= N, M<= 10)
输出
输出要找到宝物的最少需要花费的时间。(以秒为单位)
样例输入
2 2
0 2
1 3
样例输出
60
这个题是前几天刚学到的bfs求最短路径的问题,本来是很简单,几分钟就敲出来了代码,但是一直提交错误,而且一直找不到错误,最后才找到数组的下标界限弄反了...真想把自己一棒子打死......
自己太心急了,结果一心急,不淡定了,本来是一个非常小的小错误,但是心静不下来,根本没找到错在了哪里,虽然都最后调试出来了,但是不知道浪费了多少时间,更重要的是影响了自己的心情,感觉自己还是心境不行,很容易就被打乱了心神,要不然这样的小错误,绝对能错了一次就找出来
#include<stdio.h> #include<string.h> #include<queue> using namespace std; int n,m,x[20][20],v[20][20]; int fx[4]={-1,0,0,1},fy[4]={0,-1,1,0}; struct mg { int x,y; int t; }s,t; queue<mg> q; void bfs() { while(!q.empty()) { s=q.front();q.pop(); if(x[s.x][s.y]==2) { return; } for(int i=0;i<4;++i) //四个方向拓展 { int tx=s.x+fx[i],ty=s.y+fy[i]; if(tx<0||tx>n-1||ty<0||ty>m-1||x[tx][ty]==1) { continue; } if(!v[tx][ty]) //标记 { v[tx][ty]=1; t.x=tx;t.y=ty;t.t=s.t+1; q.push(t); } } } } int main() { int i,j,a,b,c; while(~scanf("%d%d",&n,&m)) { while(!q.empty()) { q.pop(); } for(i=0;i<n;++i) { for(j=0;j<m;++j) { scanf("%d",&c); x[i][j]=c; if(c==3) //从3 开始,可以防止多个起点问题 { a=i;b=j; } } } memset(v,0,sizeof(v)); //注意清零 s.x=a;s.y=b;s.t=0; v[a][b]=1; q.push(s); bfs(); printf("%d\n",s.t*60); } return 0; }
1697: 找句子(kmp匹配)
时间限制: 1 Sec 内存限制: 128 MB题目描述
给出两个字符串(全部由数字组成),求出其中一个字符串在另外一个字符串出现的位置(刚开始出现的位置),位置从1 开始。(位置从1开始)。输入
输入包括多组测试数据,每组测试数据包含三行,第一行包含两个整数n(1<=n<=1000000),m(1<=m<=1000),分别代表文章的长度,和所摘取的句子的长度,第二行包含n个整数表示文章,第三行包括m各整数表示句子
输出
输出所摘取的句子在文章中的位置样例输入
13 5 1 2 1 2 3 1 2 3 1 3 2 1 2 1 2 3 1 3
样例输出
6
提示
题目保证可以找到!!! 位置从1开始。这个题比较简单,做的时候比较顺利的就解决了,用的知识是前两天学的 kmp 快速匹配字符串的思想,只是把字符串改成了别的类型的数组,做法没什么不同,只是处理的时候注意输出的数和位置的关系,其他就问题不大,虽然自己会简单的kmp使用,但是自己对这个算法还不太理解,还需要进一步的学习。
#include<stdio.h> #include<string.h> #define maxn 10005 int p[maxn],cnt; int x[maxn],y[maxn*100],n,m; void getp() { int i=0,j=-1; p[0]=-1; while(i<m) { if(j==-1||x[i]==x[j]) { ++j;++i; p[i]=j; } else { j=p[j]; } } } void kmp() { getp(); int i=0,j=0; while(i<n) { if(j==-1||x[j]==y[i]) { ++i,++j; if(j==m-1) { cnt=i-j; //这个位置就是能匹配的首位置 } } else { j=p[j]; } } } int main() { int i; while(~scanf("%d%d",&n,&m)) { for(i=0;i<n;++i) { scanf("%d",&y[i]); } for(i=0;i<m;++i) { scanf("%d",&x[i]); } cnt=0; //注意清零 kmp(); printf("%d\n",cnt+1); } return 0; }
1690: 组合数(dfs递归)
时间限制: 3 Sec 内存限制: 128 MB题目描述
给出n个数字,每次从中取m个数,打印这m个数的所有组合。输入
输入包括多组测试数据,每组包括一行整数n(1<=n<10),m(1<=m<=n),空格间隔输出
按特定顺序输出所有组合。特定顺序:每一个组合中的值从大到小排列,组合之间按逆字典序排列。
样例输入
5 3
样例输出
543 542 541 532 531 521 432 431 421 321
这个题是个dfs 比较简单的一道模板题,但是自己对搜索理解不够透彻,掌握不够扎实,费了一段时间才把这个调试出来,看来自己还有很长的路要走,现在学的东西太少了,dfs 多层递归的控制,真的很难控制,稍微改动一点条件,结果就无法预料了,还需要自己慢慢的理解...
#include<stdio.h> #include<string.h> int n,m,vis[25],y[25],x[25]; void dfs(int v) { if(v>=m) //控制输出 { int i; for(i=0;i<m-1;++i) { printf("%d",x[i]); } printf("%d\n",x[i]); //格式 return; } for(int i=0;i<n;++i) { if(!vis[i]) { vis[i]=1; x[v]=y[i]; if(v==0||x[v]<x[v-1]) //这一步用来控制什么时候进行下一步运算,也就是满足一定的大小关系的时候 { dfs(v+1); } vis[i]=0; } } } int main() { int i; while(~scanf("%d%d",&n,&m)) { memset(vis,0,sizeof(vis)); for(i=n-1;i>=0;--i) { y[i]=n-i; //储存值 } dfs(0); } return 0; }
1696: 雇佣工人
时间限制: 1 Sec 内存限制: 128 MB题目描述
某人接到一个工程,他需要招募一些人,为了方便工作,他希望他的团队两人两人之间都是朋友关系,或者间接是朋友关系。现在有一些人来报名,他们之间的关系已知,求这个人可以招到的最大的人数是多少输入
输入包含多组测试数据,每组测试数据第一行一个n,表示来报名的人的编号1-100,后边接n行,每行两个整数a b,表示编号a和b的小伙伴是朋友关系输出
输出包括一行,即此人可以招到的最大的人数是多少样例输入
4 1 2 3 4 5 6 1 6
样例输出
4
这个题是典型的并查集的题目,题意要求的是元素最多的集合中最多有多少个元素,虽然做出来了,但是觉得自己的方法不够好,没有在压缩路径的时候直接就把所有的路径压缩完全,然后还要在最后重复压缩查找了一遍,感觉不太好,还需要再学习学习别人的好方法
#include<stdio.h> #include<string.h> int per[10005],n,cnt[10005]; void init() //初始化 { for(int i=1;i<=100;++i) { per[i]=i; } } int find(int x) //找父节点 { int r=x; if(r!=per[r]) { r=per[r]; } int i=x,j; while(i!=r) //压缩路径 { j=per[i]; per[i]=r; i=j; } return r; } void join(int x,int y) //合并 { int fx=find(x),fy=find(y); if(fx!=fy) { per[fy]=fx; } //fx=find(fy); } int main() { int i,a,b,max; while(~scanf("%d",&n)) { init(); memset(cnt,0,sizeof(cnt)); for(i=0;i<n;++i) { scanf("%d%d",&a,&b); join(a,b); } max=0; for(i=1;i<=100;++i) { a=find(per[i]); //这里再次压缩了路径 ++cnt[a]; max=max>cnt[a]?max:cnt[a]; //更新最大值 } printf("%d\n",max); } return 0; }
相关文章推荐
- 第三次周赛题解【并查集 KMP DFS BFS 快速幂】
- [leetcode] Find Minimum in Rotated Sorted Array
- [leedcode 234] Palindrome Linked List
- 让DIV中文字换行显示
- 线段树 Ⅱ
- Leetcode: Summary Ranges
- Equidistant String (周赛2)
- CF 558C 暴力,bfs
- 第18章 多线程----线程的优先级
- 编码种类
- tinyhttpd简介
- 3.2html学习笔记之图片
- 【javascript】 声明函数与函数表达式 的区别
- linux-vfs : inode number
- Lua笔记8-模块和包
- C# 枚举
- 基于unity的直升机模拟设计
- 什么是回溯法?
- HNOI2004 宠物收养所 解题报告
- 输出表文件