您的位置:首页 > 理论基础 > 数据结构算法

[置顶] 信息学奥赛一本通(C++版) 第三部分 数据结构 第二章 队列

2017-10-25 21:31 1061 查看
信息学奥赛一本通(C++版) 第三部分 数据结构 第二章 队列
http://ybt.ssoier.cn:8088
//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】围圈报数

//循环队列,取模,数列空出一个空间

//提交,未通过,运行超时

//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该章节内容
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐