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

第二章 队列

T1332 : 周末舞会

【题目描述】

  假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。规定每个舞曲能有一对跳舞者。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一个程序,模拟上述舞伴配对问题。

【输入】

  第一行两队的人数,第二行舞曲的数目。

【输出】

  配对情况。

【输入样例】

4 6
7

【输出样例】

1 1
2 2
3 3
4 4
1 5
2 6
3 1

【答案&代码】

  代码如下。

#include<stdio.h>
int main(void){
    int man,woman,ss;
    scanf("%d%d%d",&man,&woman,&ss);
    int m[man],n[woman];
    for(int i=0;i<man;i++)
        m[i]=i+1;
    for(int i=0;i<woman;i++)
        n[i]=i+1;
    int c1=0,c2=0;
    for(int i=0;i<ss;i++,c1++,c2++){
        if(c1==man||c2==woman)
            c1%=man,c2%=woman;
        printf("%d %d\n",m[c1],n[c2]);
    }
    return 0;
}

T1333 : Blah数集

【题目描述】

  大数学家高斯小时候偶然间发现一种有趣的自然数集合Blah,对于以a为基的集合Ba定义如下:

  (1)a是集合Ba的基,且a是Ba的第一个元素;

  (2)如果x在集合Ba中,则2x+1和3x+1也都在集合Ba中;

  (3)没有其他元素在集合Ba中了。

  现在小高斯想知道如果将集合Ba中元素按照升序排列,第N个元素会是多少?

【输入】

  输入包括很多行,每行输入包括两个数字,集合的基a(1≤a≤50))以及所求元素序号n(1≤n≤1000000)。

【输出】

  对于每个输入,输出集合Ba的第n个元素值。

【输入样例】

1 100
28 5437

【输出样例】

418
900585

【答案&代码】

  代码如下。

#include<stdio.h>
#include<string.h>
#include<queue>
using std::queue;
int ans[1000005];
int f(int a,int n){
    queue<int>Q1,Q2;
    int f=1,x=a;
    memset(ans,0,sizeof(ans));
    for(int i=1;i<=n;i++){
        ans[f++]=x;
        Q1.push(2*x+1),Q2.push(3*x+1);
        if(Q1.front()<Q2.front())
            x=Q1.front(),Q1.pop();
        else if(Q1.front()==Q2.front())
            x=Q1.front(),Q1.pop(),Q2.pop();
        else
            x=Q2.front(),Q2.pop();
    }
    return ans[n];
}
int main(void){
    int a,n;
    while(scanf("%d%d",&a,&n)!=EOF)
        printf("%d\n",f(a,n));
    return 0;
}

T1334 : 围圈报数

【题目描述】

  有n个人依次围成一圈,从第1个人开始报数,数到第m个人出列,然后从出列的下一个人开始报数,数到第m个人又出列,…,如此反复到所有的人全部出列为止。设n个人的编号分别为1,2,…,n,打印出列的顺序。

【输入】

  n和m。

【输出】

  出列的顺序。

【输入样例】

4 17

【输出样例】

1 3 4 2

【答案&代码】

  代码如下。

#include<stdio.h>
#include<queue>
using std::queue;
int main(void){
    int n, m, count = 1;
    queue<int>q;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        q.push(i);
    while(!q.empty())
        if (count == m)
            printf("%d ",q.front()),q.pop(),count=1;
        else
            count++,q.push(q.front()),q.pop();
    return 0;
}

T1335 : 连通块

【题目描述】

  一个n * m的方格图,一些格子被涂成了黑色,在方格图中被标为1,白色格子标为0。问有多少个四连通的黑色格子连通块。四连通的黑色格子连通块指的是一片由黑色格子组成的区域,其中的每个黑色格子能通过四连通的走法(上下左右),只走黑色格子,到达该联通块中的其它黑色格子。

【输入】

  第一行两个整数n,m(1≤n,m≤100),表示一个n * m的方格图。

  接下来n行,每行m个整数,分别为0或1,表示这个格子是黑色还是白色。

【输出】

  一行一个整数ans,表示图中有ans个黑色格子连通块。

【输入样例】

3 3
1 1 1
0 1 0
1 0 1

【输出样例】

3

【答案&代码】

  代码如下。

#include<stdio.h>
int n,m;
bool map[101][101]={0};
void fun(int x,int y){
    int cx[4]={0,0,1,-1},
        cy[4]={1,-1,0,0};
    map[x][y]=false;
    for(int i=0;i<4;i++)
        if(
            0<=x+cx[i]&&x+cx[i]<n&&
            0<=y+cy[i]&&y+cy[i]<m&&
            map[x+cx[i]][y+cy[i]]
        )
            fun(x+cx[i],y+cy[i]);
    return;
}
int main(void){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        for(int j=0,temp;j<m;j++){
            scanf("%d",&temp);
            if(temp==1)
                map[i][j]=true;
        }
    long long sum=0;
    for(int i=0;i<n;i++)
        for(int j=0,temp;j<m;j++){
            if(map[i][j])
                sum+=1,fun(i,j);
        }
    printf("%lld",sum);
    return 0;
}

T1359 : 围成面积

【题目描述】

  编程计算由“”号围成的下列图形的面积。面积计算方法是统计号所围成的闭合曲线中水平线和垂直线交点的数目。如下图所示,在10×10的二维数组中,有“*”围住了15个点,因此面积为15。
《信息学奥赛一本通(C++版)第三部分 数据结构 第二章 队列》

【输入】

  10×10的图形。

【输出】

  输出面积。

【输入样例】

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 0 0
0 0 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 1 0
0 1 0 1 0 1 0 0 1 0
0 1 0 0 1 1 0 1 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0

【输出样例】

15

【答案&代码】

  代码如下。

#include <iostream>//面积(area)
#include <cstdio>
 using namespace std; 
 int a[11][11];
 int flag,bz,ans,n;
 int main(){
    //freopen("area.in","r",stdin);
    // freopen("area.out","w",stdout);
    int i,j;
    //cin>>n;
    n=10;
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
         cin>>a[i][j];
         for(i=1;i<=n;i++)//将边缘不为1的元素置为-1 
            for(j=1;j<=n;j++)
              if(i==1||j==1||i==n||j==n)
              if(a[i][j]==0)a[i][j]=-1;
                //a[i][j]=-1;
         //for(i=1;i<=n;i++){
           //if(j==n+1)cout<<endl;
          //for(j=1;j<=n;j++)
         //cout<<a[i][j]<<" ";}
         //cout<<endl;
        for(i=2;i<n;i++)//枚举边缘外的所有元素 
          for(j=2;j<n;j++){flag=0;
            if(a[i][j]==0){ 
            if(flag==0){
              for(int jl=j-1;jl>=1;jl--){//查找第i行第j列的左边有没有元素1或-1 
                if(a[i][jl]==-1){a[i][j]=-1;flag=1;break;   }
                else if(a[i][jl]==1)break;}}
                if(flag==0){
              for(int jr=j+1;jr<=n;jr++){//查找第i行第j列的右边有没有元素1或-1 
                if(a[i][jr]==-1){a[i][j]=-1;flag=1;break;   }
                else if(a[i][jr]==1)break;}}
                if(flag==0){
              for(int is=i-1;is>=1;is--){////查找第j列第i行的左边有没有元素1或-1 
                if(a[is][j]==-1){a[i][j]=-1;flag=1;break;   }
                else if(a[is][j]==1)break;}}
                if(flag==0){
              for(int ix=i+1;ix<=n;ix++){////查找第j列第i行的右边有没有元素1或-1 
                if(a[ix][j]==-1){a[i][j]=-1;flag=1;break;   }
                else if(a[ix][j]==1)break;}}
            }
        }


         //for(i=1;i<=n;i++){
          // if(j==n+1)cout<<endl;
          //for(j=1;j<=n;j++)
         //cout<<a[i][j]<<" ";}
         //cout<<endl;
        for(i=1;i<=n;i++)
         for(j=1;j<=n;j++)
         if(a[i][j]==0)ans++;   
     cout<<ans;    
}

T1360 : 奇怪的电梯(lift)

【题目描述】

  大楼的每一层楼都可以停电梯,而且第i层楼(1≤i≤N)上有一个数字Ki(0≤=Ki≤=N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3 3 1 2 5代表了Ki(K1=3,K2=3,……),从一楼开始。在一楼,按“上”可以到4楼,按“下”是不起作用的,因为没有-2楼。那么,从A楼到B楼至少要按几次按钮呢?

【输入】

  共有二行,第一行为三个用空格隔开的正整数,表示N,A,B(1≤N≤200, 1≤A,B≤N),第二行为N个用空格隔开的正整数,表示Ki。

【输出】

  一行,即最少按键次数,若无法到达,则输出-1。

【输入样例】

5 1 5
3 3 1 2 5

【输出样例】

3

【答案&代码】

  代码如下。

#include<stdio.h>
int n,a,b,k[205];
int f[205]={0};
int min(int a,int b){
    return a<b?a:b;
}
bool bfs(int now,int st){
    if(now<0)
        return false;
    else if(now==b)
        return f[now]=min(st,f[now]);
    else{
        f[now]=min(st,f[now]);
        if(st!=0&&f[now]<st)
            return false;
        else{
            bool f1=bfs(now+k[now],st+1),f2=bfs(now-k[now],st+1);
            return f1||f2;
        }

    }
}
int main(void){
    for(int i=0;i<205;i++)
        f[i]=0X3F3F3F3F;
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++)
        scanf("%d",&k[i]);
    if(bfs(a,0))
        printf("%d",f[b]);
    else if(a==b)
        printf("0");
    else
        printf("-1");
    return 0;
}

T1361 : 产生数(Produce)

【题目描述】

  给出一个整数n(n≤2000)和k个变换规则(k≤15)。规则:

  ① 1个数字可以变换成另1个数字;

  ② 规则中,右边的数字不能为零。

  例如:n=234,k=2规则为

  2 → 5

  3 → 6

  上面的整数234经过变换后可能产生出的整数为(包括原数)234,534,264,564共4种不同的产生数。

  求经过任意次的变换(0次或多次),能产生出多少个不同的整数。仅要求输出不同整数个数。

【输入】

  n
  k
  x1 y1
  x2 y2
  … …
  xn yn

【输出】

  格式为一个整数(满足条件的整数个数)。

【输入样例】

234
2
2 5
3 6

【输出样例】

4

【答案&代码】

  代码如下。

#include<stdio.h>
#include<string.h>
char s1[40];
int l,a[40],k,ans[101];
int nnn;
int x[16],y[16],hash[10];
void DFS(int v){
    for(int i=1;i<=k;i++)
        if(v==x[i]&&hash[y[i]]==0)
            hash[y[i]]++,DFS(y[i]);
}
int main(void){
    int m=0;
    scanf("%s%d",s1,&k);
    l=strlen(s1);
    for(int i=1;i<=k;i++)
        scanf("%d%d",&x[i],&y[i]);
    ans[1]=1;
    for(int i=1;i<=l;i++)
    {
        memset(hash,0,sizeof(hash));
        nnn=1;
        a[i]=s1[i-1]-'0';
        DFS(a[i]);
        for(int j=0;j<=9;j++)
        {
            if(hash[j]!=0&&j!=a[i]) nnn++;
        }
        for(int j=1;j<=100;j++)
        {
            ans[j]=ans[j]*nnn+m;
            m=0;
            if(ans[j]>=10) {m=ans[j]/10;ans[j]=ans[j]%10;}
        }
    }
    for(int i=1;i<=100;i++)
        if(ans[i]!=0)
            l=i;
    for(int i=l;i>=1;i--)
    printf("%d",ans[i]);
    return 0;
}

T1362 : 家庭问题(family)

【题目描述】

  有n个人,编号为1,2,……n,另外还知道存在K个关系。一个关系的表达为二元组(α,β)形式,表示α,β为同一家庭的成员。

  当n,k和k个关系给出之后,求出其中共有多少个家庭、最大的家庭中有多少人?

  例如:n=6,k=3,三个关系为(1,2),(1,3),(4,5)

  此时,6个人组成三个家庭,即:{1,2,3}为一个家庭,{4,5}为一个家庭,{6}单独为一个家庭,第一个家庭的人数为最多。

【输入】

  第一行为n,k二个整数(1≤n≤100)(用空格分隔);

  接下来的k行,每行二个整数(用空格分隔)表示关系。

【输出】

  二个整数(分别表示家庭个数和最大家庭人数)。

【输入样例】

6 3
1 2
1 3
4 5

【输出样例】

3 3

【答案&代码】

  代码如下。

#include<stdio.h>
int to[105],f[105];
int max(int a,int b){
    return a>b?a:b;
}
int main(void){
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        f[i]=1;
    for(int i=1,a,b;i<=k;i++){
        scanf("%d%d",&a,&b);
        if(a>b)
            a+=b,b=a-b,a=a-b;
        to[b]=a;
    }
    for(int i=n;i>=1;i--){
        if(to[i]!=0)
            f[to[i]]+=f[i],f[i]=0;
    }
    int maxn=0,ans=0;
    for(int i=1;i<=n;i++){
        maxn=max(maxn,f[i]);
        if(f[i]!=0)
            ans++;
    }
    printf("%d %d",ans,maxn);
    return 0;
}
    原文作者:舞伴问题
    原文地址: https://blog.csdn.net/Lu_Anlai/article/details/80390396
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞