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

信息学奥赛一本通(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该章节内容


猜你喜欢

转载自blog.csdn.net/mrcrack/article/details/78346997