您的位置:首页 > 其它

几道周赛题目(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: