信息学奥赛一本通(C++版) 第三部分 数据结构 第二章 队列
http://ybt.ssoier.cn:8088
//1332 【例2-1】周末舞会
//样例通过,提交AC
//感觉这次写的代码很队列。2018-5-9 21:17
#include <stdio.h>
#define maxn 1000
int boy[maxn],girl[maxn];
int main(){
int bh,bt,gh,gt,b,g,i,n,bo,gi;
scanf("%d%d%d",&b,&g,&n);
for(i=1;i<=b;i++)boy[i]=i;
bh=1,bt=b+1;
for(i=1;i<=g;i++)girl[i]=i;
gh=1,gt=g+1;
for(i=1;i<=n;i++){
bo=boy[bh];
gi=girl[gh];
printf("%d %d\n",bo,gi);
boy[bt]=bo,bt++,girl[gt]=gi,gt++;
bh++,gh++;
}
return 0;
}
//1332 【例2-1】周末舞会
#include <stdio.h>
int p[100000],q[100000];
int main(){
int h1,t1,h2,t2,a,b,n,i;
scanf("%d%d%d",&a,&b,&n);
h1=t1=1;
for(i=1;i<=a;i++){
p[t1]=i;
t1++;
}
h2=t2=1;
for(i=1;i<=b;i++){
q[t2]=i;
t2++;
}
for(i=1;i<=n;i++){
printf("%d %d\n",p[h1],q[h2]);
p[t1]=p[h1],t1++,h1++;
q[t2]=q[h2],t2++,h2++;
}
return 0;
}
//1333 【例2-2】Blah数集
//http://blog.csdn.net/lengxuenong/article/details/50497010
//http://blog.csdn.net/cax1165/article/details/52937683
//http://blog.csdn.net/qq_35640373/article/details/70168609
//三篇文章都写得不错
//双指针单调队列
#include <stdio.h>
int q[1000100];
int main(){
int h1,h2,t,a,n,x,y;
while(scanf("%d%d",&a,&n)!=EOF){
h1=h2=t=1;
q[t]=a,t++;
while(t<=n){
x=q[h1]*2+1,y=q[h2]*3+1;//此处写成 x=q[h1]*2+1,y=q[h1]*3+1;
if(x<y){
q[t]=x,t++,h1++;
}else if(x>y){
q[t]=y,t++,h2++;
}else{//x==y
q[t]=x,t++,h1++,h2++;
}
}
printf("%d\n",q[t-1]);
}
return 0;
}
//1334 【例2-3】围圈报数
//样例通过,提交AC 2018-5-9
//发现代码还是写得很队列。2018-5-9 21:28
#include <stdio.h>
#define maxn 1000
int q[maxn];
int main(){
int n,m,h,t,i,p,cnt=0;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
q[i]=i;
h=1,t=n+1;
while(h<t){
p=q[h];
cnt++;
if(cnt==m){
cnt=0;
printf("%d ",p);
}else
q[t]=p,t++;
h++;
}
return 0;
}
//1334 【例2-3】围圈报数
//循环队列,取模,数列空出一个空间
//提交,未通过,运行超时
//90分代码
#include <stdio.h>
int q[10000];
int main(){
int n,m,h,t,i,mod;
scanf("%d%d",&n,&m);
h=t=1,mod=n+1;
for(i=0;i<n;i++)q[t++]=i;
while(h!=t){
for(i=1;i<m;i++){
q[t]=q[h];
t=(t+1)%mod,h=(h+1)%mod;
}
printf("%d ",q[h]+1);
h=(h+1)%mod;
}
return 0;
}
//1334 【例2-3】围圈报数
//循环队列,取模,数列空出一个空间
//提交,未通过,运行超时
//改变思路,每次删除,数组变换一次。提交,AC
#include <stdio.h>
#include <string.h>
int a[10000],b[10000];
int main(){
int n,m,i,mod,cnt;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)a[i]=i,b[i]=i;
cnt=n;
while(cnt>0){
printf("%d ",a[(m-1)%cnt]+1);
cnt--;
for(i=0;i<cnt;i++)a[i]=b[((m-1)%(cnt+1)+1+i)%(cnt+1)];
memcpy(b,a,sizeof(a));
}
return 0;
}
//1335 【例2-4】连通块
#include <stdio.h>
#include <string.h>
struct node{
int row,col;
}q[10100],p;
int vis[110][110],a[110][110],next[][2]={{-1,0},{1,0},{0,-1},{0,1}};
int main(){
int n,m,i,j,h,t,k,nr,nc,cnt=0;
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(vis[i][j]==0&&a[i][j]==1){
cnt++;
vis[i][j]=1;
h=t=1;
q[t].row=i,q[t].col=j;
t++;
while(h<t){
p=q[h];
for(k=0;k<4;k++){
nr=p.row+next[k][0];
nc=p.col+next[k][1];
if(vis[nr][nc]==0&&a[nr][nc]==1){
vis[nr][nc]=1;
q[t].row=nr,q[t].col=nc;
t++;
}
}
h++;
}
}
printf("%d",cnt);
return 0;
}
//1359 围成面积
//第一遍,将外围的0全部置为1
//第二遍,输出内部0的个数
//样例通过,测试点2,3,5答案错误
//网络中下载了该题的测试数据,才明白,几乎是不可能编出的
//测试点2
//输入:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 1 1
//输出:
0
//测试点3
//输入:
0 0 0 0 1 1 0 0 0 0
0 0 0 1 0 1 0 0 0 0
0 0 1 0 0 1 0 0 0 0
0 1 0 0 0 1 0 0 0 0
1 0 0 1 1 1 0 0 0 0
0 1 1 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 1 0 0 0 1
0 0 0 0 0 1 1 1 1 1
//输出:
11
//测试点5
//输入:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0 0 0
0 0 0 1 0 0 1 1 1 0
0 0 0 0 1 1 0 0 0 1
0 0 0 0 0 1 0 0 1 0
0 0 0 1 1 0 0 1 0 0
0 0 0 1 0 0 0 1 0 0
0 0 0 0 1 1 1 0 0 0
//输出:
12
//对着样例修改代码,提交AC 2017-11-10 20:37
#include <stdio.h>
#include <string.h>
int a[15][15],vis[15][15],next[][2]={{-1,0},{1,0},{0,-1},{0,1}},cnt=0;
struct node{
int r,c;
}q[200];
void bfs(int i,int j){
int r,c,nr,nc,h,t,k;
h=t=1;
vis[i][j]=1,a[i][j]=1;
q[t].r=i,q[t].c=j,t++;
while(h<t){
r=q[h].r,c=q[h].c;
for(k=0;k<4;k++){
nr=r+next[k][0],nc=c+next[k][1];
if(1<=nr&&nr<=10&&1<=nc&&nc<=10&&a[nr][nc]==0&&vis[nr][nc]==0){
vis[nr][nc]=1,a[nr][nc]=1;
q[t].r=nr,q[t].c=nc,t++;
}
}
h++;
}
}
void bfs_cnt(int i,int j){
int r,c,nr,nc,h,t,k;
h=t=1;
vis[i][j]=1;
q[t].r=i,q[t].c=j,t++,cnt++;
while(h<t){
r=q[h].r,c=q[h].c;
for(k=0;k<4;k++){
nr=r+next[k][0],nc=c+next[k][1];
if(1<=nr&&nr<=10&&1<=nc&&nc<=10&&a[nr][nc]==0&&vis[nr][nc]==0){
vis[nr][nc]=1,cnt++;
q[t].r=nr,q[t].c=nc,t++;
}
}
h++;
}
}
int main(){
int i,j;
memset(vis,0,sizeof(vis));
for(i=1;i<=10;i++)
for(j=1;j<=10;j++)
scanf("%d",&a[i][j]);
//处理外围的0点
for(j=1;j<=10;j++)if(a[1][j]==0)bfs(1,j);
for(j=1;j<=10;j++)if(a[10][j]==0)bfs(10,j);
for(i=1;i<=10;i++)if(a[1][i]==0)bfs(1,i);
for(i=1;i<=10;i++)if(a[10][i]==0)bfs(10,i);
//统计内部的点 ,存在多区块,需多次统计
for(i=1;i<=10;i++)
for(j=1;j<=10;j++)
if(a[i][j]==0&&vis[i][j]==0)//此处写成 if(a[i][j]==0)
bfs_cnt(i,j);
printf("%d",cnt);
return 0;
}
//1360 奇怪的电梯(lift)
//http://ybt.ssoier.cn:8088
//洛谷 P1135 奇怪的电梯
//https://www.luogu.org/problemnew/show/1135
//该题题目读起来,比较累
//要是能将样例的实现有一个详细说明该有多好啊。
//对 如果不能满足要求,相应的按钮就会失灵。 产生误解,到了相应楼层可以不按键,电梯会自行前往可行的楼层,在这个想法里僵持了很久
//看了他人代码,才明白,到了楼层以后,必按按钮,只是能去的楼层,按按钮有效,不能去的楼层,按按钮无效
//样例分析如下:
//1楼 按上 到 1+3=4楼
//4楼 按下 到 4-2=2楼
//2楼 按上 到 2+3=5楼
//插一句,题目中给的按钮,开,关是多余的,在解题中没有用到,这句也困扰了很久,一直在想,按开算一次,按关算一次。
//源自老外的题,翻译确实很差劲。
//该题,难在破题,编码挺简单的
//样例通过,提交AC 2017-11-10 22:37
#include <stdio.h>
#include <string.h>
int a[300],vis[300];
struct node{
int x,s;//s按键次数
}q[300];
int main(){
int n,start,end,i,cnt=0,h,t,x,nx,s;
memset(vis,0,sizeof(vis));
scanf("%d%d%d",&n,&start,&end);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
h=t=1;
q[t].x=start,q[t].s=0,t++,vis[start]=1;//请注意q[t].s=0而不是1
while(h<t){
x=q[h].x,s=q[h].s;
if(x==end){
printf("%d",s);
return 0;
}
nx=x+a[x];
if(1<=nx&&nx<=n&&vis[nx]==0){
q[t].x=nx,q[t].s=s+1,vis[nx]=1,t++;
}
nx=x-a[x];
if(1<=nx&&nx<=n&&vis[nx]==0){
q[t].x=nx,q[t].s=s+1,vis[nx]=1,t++;
}
h++;
}
printf("-1");
return 0;
}
//1361 产生数(Produce)
//题目容易看懂,但没什么思路
//觉得怎么确定某个数据已经生成过,是该题的难点
//用字符串作为中介,查找其中的元素,以及转化成数字比较方便 ,并且无需考虑输入数据的长度
//什么是队列,一个一个按部就班,即是队列
//提交,只有测试点1 答案正确
//看了测试点2的数据后,程序做小的修改,看了测试点3的数据,程序只能做大的改动,编的时候不知道数据的给出形式,编了功能很狭隘的程序
//测试点2 输入:
1234
3
2 3
3 2
3 5
//输出:
9
//测试点3 输入:
1111
2
1 2
2 1
//输出:
16
//测试点5 输入:
7070
7
0 1
0 2
0 7
7 1
7 2
7 3
2 7
//输出:
400
//大幅修改后,提交AC 2017-11-11 12:28
//没有上述数据,该题很难编出。
#include <stdio.h>
#include <string.h>
int vis[10100];//此处写成int vis[2100],n经变换,最大值可到9999;// vis[]当前数据是否访问过
char s[10],q[10100][10]; //此处写成 char s[10],q[1000][10];
struct node{
int x,y;
}b[20];//b[]变换规则
int s2i(char s[],int len){//字符串转成数字
int i,ans=0;
for(i=0;i<len;i++){//此处写成for(i=len-1;i>=0;i--) 低级中的低级
ans*=10;
ans+=s[i]-'0';//此处写成 ans+=s[i];低级错误
}
return ans;
}
int main(){
int i,len,k,cnt=1,x,y,h,t,d,j;
char s_t[10];
memset(vis,0,sizeof(vis));
scanf("%s",s);
len=strlen(s);
scanf("%d",&k);
for(i=1;i<=k;i++)scanf("%d%d",&b[i].x,&b[i].y);
h=t=1;
strcpy(q[t],s),t++;
vis[s2i(s,len)]=1;
while(h<t){
for(i=1;i<=k;i++){
strcpy(s_t,q[h]);
for(j=0;j<len;j++)
if(s_t[j]==b[i].x+'0'){
s_t[j]=b[i].y+'0';
d=s2i(s_t,len);
if(vis[d]==0){
vis[d]=1;
strcpy(q[t],s_t),t++,cnt++;
}
strcpy(s_t,q[h]);//初始化s_t
}
}
h++;
}
printf("%d",cnt);
return 0;
}
//1362 家庭问题(family)
//看完题目,第一直觉,并查集
//先试试看,再考虑队列
//并查集很快AC,2017-11-11 16:21在考虑并查集递归的深度最多能到多少
//现在可以放心的研究队列了。
#include <stdio.h>
#include <string.h>
int f[110],b[110];
int getf(int u){
if(f[u]==u)return u;
return f[u]=getf(f[u]);
}
void merge(int u,int v){//左靠
int f1=getf(u),f2=getf(v);
if(f1!=f2)f[f2]=f1;
}
int main(){
int n,k,i,u,v,cnt_1=0,cnt_2=0;
memset(b,0,sizeof(b));
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)f[i]=i;
for(i=1;i<=k;i++){
scanf("%d%d",&u,&v);
merge(u,v);
}
for(i=1;i<=n;i++)b[getf(i)]++;//统计家庭成员
for(i=1;i<=n;i++)
if(b[i]>cnt_2)
cnt_2=b[i];
for(i=1;i<=n;i++)
if(f[i]==i)
cnt_1++;
printf("%d %d",cnt_1,cnt_2);
}
2017-11-11 16:33 AC该章节内容