總述
題目概述
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;
}