1. 程式人生 > >資訊學奧賽一本通(C++版) 第三部分 資料結構 第二章 佇列

資訊學奧賽一本通(C++版) 第三部分 資料結構 第二章 佇列

//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該章節內容