CSP真題_2015_3 畫圖(BFS在csp考題中的應用場景)

總述

題目概述

BFS是算法中比較簡單和初級的算法,但由於其在解決圖論及一些多維空間問題上的易實現性,在很多程序設計題目中頻繁出現。在解決問題時,如果設計出了一個BFS或其同類的DFS算法,只要證明這個算法在時空複雜度上都滿足條件,就可以果斷實現。如果發現部分數據無法滿足,且當前沒有其他好的思路,也可以將其作爲一種得部分分數的方式在CSP中使用。

原題描述

問題描述
用 ASCII 字符來畫圖是一件有趣的事情,並形成了一門被稱爲 ASCII Art 的藝術。
本題要求編程實現一個用 ASCII 字符來畫圖的程序,支持以下兩種操作:
1、畫線:給出兩個端點的座標,畫一條連接這兩個端點的線段。簡便起見題目保證要畫的每條線段都是水平或者豎直的。水平線段用字符 - 來畫,豎直線段用字符 | 來畫。如果一條水平線段和一條豎直線段在某個位置相交,則相交位置用字符 + 代替。
2、填充:給出填充的起始位置座標和需要填充的字符,從起始位置開始,用該字符填充相鄰位置,直到遇到畫布邊緣或已經畫好的線段。注意這裏的相鄰位置只需要考慮上下左右 4 個方向。

INPUT

第1行有三個整數m, n和q。m和n分別表示畫布的寬度和高度,以字符爲單位。q表示畫圖操作的個數。
第2行至第q + 1行,每行是以下兩種形式之一:

  • 0 x1 y1 x2 y2:表示畫線段的操作,(x1, y1)和(x2, y2)分別是線段的兩端,滿足要麼x1 = x2 且y1 ≠ y2,要麼 y1 = y2 且 x1 ≠ x2。
  • 1 x y c:表示填充操作,(x, y)是起始位置,保證不會落在任何已有的線段上;c 爲填充字符,是大小寫字母。

畫布的左下角是座標爲 (0, 0) 的位置,向右爲x座標增大的方向,向上爲y座標增大的方向。這q個操作按照數據給出的順序依次執行。畫布最初時所有位置都是字符 .(小數點)。

OUTPUT

輸出有n行,每行m個字符,表示依次執行這q個操作後得到的畫圖結果。

輸入輸出案例

樣例一
輸入:

4 2 3
1 0 0 B
0 1 0 2 0
1 0 0 A

輸出:

AAAA
A----A

樣例二
輸入:

16 13 9
0 3 1 12 1
0 12 1 12 3
0 12 3 6 3
0 6 3 6 9
0 6 9 12 9
0 12 9 12 11
0 12 11 3 11
0 3 11 3 1
1 4 2 C

輸出:
在這裏插入圖片描述

題目重述

給定一個要輸出的畫布大小(長m×寬n)和要進行的操作個數q個。且該畫布的所有點被初始化爲’’.’’,初始狀態沒有畫線。
操作一共有兩種:
操作提示符爲0則是畫線操作,從輸入的(x1,y1)到(x2,y2)畫線,且注意題目的輸入數據保證完成一次畫線所畫出的一定是一條直線,也就是一定有x1==x2或者y1==y2。
操作提示符爲1,則是填充操作,從給定的出發點(x,y)開始填充輸入的字符,到達畫布的邊界或者畫出的線填充停止。(明顯是迷宮問題的改版)
輸出時,輸出每個位置的字符,有如下幾種情況:
1、有橫線有豎線,輸出“+”
2、有橫線無豎線,輸出“-”
3、無橫線有豎線,輸出“|”
4、無橫線無豎線,有填充,輸出填充字符
5、無橫線無豎線,無填充,輸出“.”
且要注意的是輸出畫布是從畫布的最上方開始輸出,要注意輸出時的遍歷參數。
題目的背景與字符串有關,看似是一道字符串題目,但只要大致理解題意我們就會發現這是一道典型的BFS題目。主要考察的就是對於數據存儲的功力,而BFS部分則可以經過轉換,變成和迷宮問題一樣情景的板子題,在算法設計上沒有太大難度。

解題思路

思路概述

關於輸入輸出部分只是一些特判,在此處就不加說明了。
關於畫線操作,由於規定一定畫直線,只需要分情況討論直線的走向和存儲,在算法設計上沒有難度。畫線操作的函數如下:

void make_line(int x_1,int y_1,int x_2,int y_2)
{
    if(x_1==x_2)//縱向劃線
    {
        if(y_1==y_2)//不劃線
        return;
        else if(y_1>y_2)//向下劃線
        {
            for(int i=y_2;i<=y_1;i++)
            {
                a[x_1][i].long_direct=1;
            }
        }
        else
        {
            for(int i=y_1;i<=y_2;i++)//向上劃線
            {
                a[x_1][i].long_direct=1;
            }
        }
    }
    else if(y_1==y_2)//橫向劃線
    {
        if(x_1>x_2)//向左劃線
        {
            for(int i=x_2;i<=x_1;i++)
            {
                a[i][y_1].wide_direct=1;
            }
        }
        else
        {
            for(int i=x_1;i<=x_2;i++)
            {
                a[i][y_1].wide_direct=1;
            }
        }   
    }
}

在填充部分,核心算法便是迷宮問題的板子。要注意的是,邊界條件較多有下列幾個:
1、BFS只在xy的正半軸進行,也就是要滿足BFS到的點滿足橫縱座標>=0
2、BFS到的點不能超過畫布的範圍,橫縱座標滿足<width,length
3、BFS過程中只有遇到橫劃線和縱劃線都滿足flag==0,纔將該點push進隊列中,且要注意後面的填充要覆蓋前面的填充。
填充部分代碼如下:

void BFS_fill(int start_x,int start_y,char filling)
{
    if(a[start_x][start_y].wide_direct==1 || a[start_x][start_y].long_direct==1)
    {
        return;
    }
    a[start_x][start_y].filling=filling;

    pos start;
    start.x=start_x;
    start.y=start_y;
    q.push(start);
    while(!q.empty())
    {
        pos node=q.front();
        q.pop();

        for(int i=0;i<4;i++)
        {
            int new_node_x=node.x+dx[i];
            int new_node_y=node.y+dy[i];
            if(a[new_node_x][new_node_y].wide_direct==0 && a[new_node_x][new_node_y].long_direct==0 && a[new_node_x][new_node_y].filling!=filling && new_node_x<wideth && new_node_y<length && new_node_x>=0 && new_node_y>=0)
            {
                a[new_node_x][new_node_y].filling=filling;
                pos new_node;
                new_node.x=new_node_x;
                new_node.y=new_node_y;
                q.push(new_node);
            }
        }
    }
}

總結

這題還蠻水的,只要注意好各個邊界條件,翻車機率不大。

題目源碼(c++)

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

struct point
{
    int wide_direct;//橫向線
    int long_direct;//縱向線
    char filling;
};

struct pos
{
    int x;
    int y;
};

int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};

point a[101][101];
int wideth,length=0;
queue<pos> q;

void BFS_fill(int start_x,int start_y,char filling)
{
    if(a[start_x][start_y].wide_direct==1 || a[start_x][start_y].long_direct==1)
    {
        return;
    }
    a[start_x][start_y].filling=filling;

    pos start;
    start.x=start_x;
    start.y=start_y;
    q.push(start);
    while(!q.empty())
    {
        pos node=q.front();
        q.pop();

        for(int i=0;i<4;i++)
        {
            int new_node_x=node.x+dx[i];
            int new_node_y=node.y+dy[i];
            if(a[new_node_x][new_node_y].wide_direct==0 && a[new_node_x][new_node_y].long_direct==0 && a[new_node_x][new_node_y].filling!=filling && new_node_x<wideth && new_node_y<length && new_node_x>=0 && new_node_y>=0)
            {
                a[new_node_x][new_node_y].filling=filling;
                pos new_node;
                new_node.x=new_node_x;
                new_node.y=new_node_y;
                q.push(new_node);
            }
        }
    }
}
void make_line(int x_1,int y_1,int x_2,int y_2)
{
    if(x_1==x_2)//縱向劃線
    {
        if(y_1==y_2)//不劃線
        return;
        else if(y_1>y_2)//向下劃線
        {
            for(int i=y_2;i<=y_1;i++)
            {
                a[x_1][i].long_direct=1;
            }
        }
        else
        {
            for(int i=y_1;i<=y_2;i++)//向上劃線
            {
                a[x_1][i].long_direct=1;
            }
        }
    }
    else if(y_1==y_2)//橫向劃線
    {
        if(x_1>x_2)//向左劃線
        {
            for(int i=x_2;i<=x_1;i++)
            {
                a[i][y_1].wide_direct=1;
            }
        }
        else
        {
            for(int i=x_1;i<=x_2;i++)
            {
                a[i][y_1].wide_direct=1;
            }
        }   
    }
}
void output()
{
    for(int j=length-1;j>=0;j--)
    {
        for(int i=0;i<wideth;i++)
            {
                if(a[i][j].long_direct==1 && a[i][j].wide_direct==1)
                printf("+");
                else if(a[i][j].long_direct==1 && a[i][j].wide_direct==0)
                printf("|");
                else if(a[i][j].long_direct==0 && a[i][j].wide_direct==1)
                printf("-");
                else if(a[i][j].long_direct==0 && a[i][j].wide_direct==0)
                printf("%c",a[i][j].filling);
            }
            printf("\n");
    }
}
int main()
{
    int done_num=0;
    int control_num=0;
    int x_1,x_2,y_1,y_2=0;
    int x,y=0;
    char str;
    scanf("%d %d %d",&wideth,&length,&done_num);
    for(int i=0;i<wideth;i++)
        for(int j=0;j<length;j++)
            a[i][j].long_direct=0,a[i][j].wide_direct=0,a[i][j].filling='.';
    for(int i=0;i<done_num;i++)
    {
        scanf("%d",&control_num);
        if(control_num==0)
        {
            scanf("%d %d %d %d",&x_1,&y_1,&x_2,&y_2);
            make_line(x_1,y_1,x_2,y_2);
        }
        else
        {
            scanf("%d %d %c",&x,&y,&str);
            BFS_fill(x,y,str);
        }
    }
    output();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章