城堡问题-双重解法 发表于 2022-04-11 更新于 2022-04-11
字数总计 1.5k 阅读时长 6分钟 阅读量
注意 该博客是为了帮助同学学习,并非为了协助同学刷题,请读者保持自觉,请勿做CV工具人 。另外为了节省篇幅,代码中不再写明#include
及using
,如果遇到我没有声明的函数或类,那么就是某一个头文件中的函数,读者搜索“std + 名字”就能查到相关信息。
感谢HZA
大佬帮忙提交测试代码
题干 点击查看原题链接(AcWing)
图1是一个城堡的地形图。请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成m*n
(m ≤ 50,n ≤ 50)个方块,每个方块可以有0 ~ 4
面墙。
输入格式 程序从标准输入设备读入数据。第一行是两个整数,分别是南北向、东西向的方块数。在接下来的输入行里,每个方块用一个数字(0 ≤ p ≤ 50)描述。用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。城堡的内墙被计算两次,方块(1, 1)的南墙同时也是方块(2, 1)的北墙。输入的数据保证城堡至少有两个房间。
输出格式 城堡的房间数、城堡中最大房间所包括的方块数。结果显示在标准输出设备上。
输入样例 在这里给出一组输入。例如:
4 7 11 6 11 6 3 10 6 7 9 6 13 5 15 5 1 10 12 7 13 7 5 13 11 10 8 10 12 13
输出样例 在这里给出相应的输出。例如:
9 5
解题过程 这道题大眼一看就是使用深度优先搜索(DFS)进行搜索,直接给出代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 bool input[ 50 ] [ 50 ] [ 4 ] ; bool vis[ 50 ] [ 50 ] ; int height, width; int solve ( int _x, int _y) { static pair< int , int > all[ ] = { { - 1 , 0 } , { 0 , - 1 } , { 1 , 0 } , { 0 , 1 } } ; int result = 0 ; stack< pair< int , int >> stack; stack. emplace ( _x, _y) ; do { auto node = stack. top ( ) ; stack. pop ( ) ; int x = node. first, y = node. second; if ( vis[ y] [ x] ) continue ; vis[ y] [ x] = true ; ++ result; for ( int i = 0 ; i != 4 ; ++ i) { int nx = x + all[ i] . first; int ny = y + all[ i] . second; if ( ny == - 1 || nx == - 1 || ny == height || nx == width) continue ; if ( input[ y] [ x] [ i] && input[ ny] [ nx] [ ( i + 2 ) % 4 ] ) stack. emplace ( nx, ny) ; } } while ( ! stack. empty ( ) ) ; return result; } int main ( ) { ios:: sync_with_stdio ( false ) ; int value; cin >> height >> width; for ( int y = 0 ; y != height; ++ y) { for ( int x = 0 ; x != width; ++ x) { cin >> value; for ( int i = 0 ; i != 4 ; ++ i) { input[ y] [ x] [ i] = ! ( ( value >> i) & 1 ) ; } } } int amount = 0 ; int maxValue = 0 ; for ( int y = 0 ; y != height; ++ y) { for ( int x = 0 ; x != width; ++ x) { if ( ! vis[ y] [ x] ) { ++ amount; maxValue = max ( maxValue, solve ( x, y) ) ; } } } printf ( "%d\n%d" , amount, maxValue) ; return 0 ; }
广度优先搜索(BFS)也是可以的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 bool input[ 50 ] [ 50 ] [ 4 ] ; bool vis[ 50 ] [ 50 ] ; int height, width; int solve ( int _x, int _y) { static pair< int , int > all[ ] = { { - 1 , 0 } , { 0 , - 1 } , { 1 , 0 } , { 0 , 1 } } ; int result = 0 ; queue< pair< int , int >> queue; queue. emplace ( _x, _y) ; do { auto node = queue. front ( ) ; queue. pop ( ) ; int x = node. first, y = node. second; if ( vis[ y] [ x] ) continue ; vis[ y] [ x] = true ; ++ result; for ( int i = 0 ; i != 4 ; ++ i) { int nx = x + all[ i] . first; int ny = y + all[ i] . second; if ( ny == - 1 || nx == - 1 || ny == height || nx == width) continue ; if ( input[ y] [ x] [ i] && input[ ny] [ nx] [ ( i + 2 ) % 4 ] ) queue. emplace ( nx, ny) ; } } while ( ! queue. empty ( ) ) ; return result; } int main ( ) { ios:: sync_with_stdio ( false ) ; int value; cin >> height >> width; for ( int y = 0 ; y != height; ++ y) { for ( int x = 0 ; x != width; ++ x) { cin >> value; for ( int i = 0 ; i != 4 ; ++ i) { input[ y] [ x] [ i] = ! ( ( value >> i) & 1 ) ; } } } int amount = 0 ; int maxValue = 0 ; for ( int y = 0 ; y != height; ++ y) { for ( int x = 0 ; x != width; ++ x) { if ( ! vis[ y] [ x] ) { ++ amount; maxValue = max ( maxValue, solve ( x, y) ) ; } } } printf ( "%d\n%d" , amount, maxValue) ; return 0 ; }
这道题使用并查集也是可以写的,每次相连的时候尝试连接两个垂直的方向(比如左面和上面)即可,最后再用map
统计结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 struct { bool link[ 4 ] { } ; int index = 0 ; } input[ 50 ] [ 50 ] ; int check[ 50 * 50 ] ; int height, width; int find ( int index) { if ( index == check[ index] ) return index; return check[ index] = find ( check[ index] ) ; } void tryLink ( int x, int y, bool hor) { int direct = hor ? 0 : 1 ; int nx = hor ? x - 1 : x; int ny = hor ? y : y - 1 ; if ( nx == - 1 || ny == - 1 || nx == width || ny == height) return ; if ( input[ y] [ x] . link[ direct] && input[ ny] [ nx] . link[ direct + 2 ] ) { check[ find ( input[ y] [ x] . index) ] = find ( input[ ny] [ nx] . index) ; } } void solve ( int index) { for ( int y = 0 ; y != height; ++ y) { for ( int x = 0 ; x != width; ++ x) { tryLink ( x, y, true ) ; tryLink ( x, y, false ) ; } } map< int , int > record; int ans = 0 ; for ( int i = 0 ; i != index; ++ i) ans = max ( ans, ++ record[ find ( i) ] ) ; printf ( "%lu\n%d" , record. size ( ) , ans) ; } int main ( ) { ios:: sync_with_stdio ( false ) ; int value, index = 0 ; cin >> height >> width; for ( int y = 0 ; y != height; ++ y) { for ( int x = 0 ; x != width; ++ x) { cin >> value; check[ index] = index; input[ y] [ x] . index = index++ ; for ( int i = 0 ; i != 4 ; ++ i) { input[ y] [ x] . link[ i] = ! ( ( value >> i) & 1 ) ; } } } solve ( index) ; return 0 ; }
小结 这两大类方法看下来是并查集的逻辑更简单,不过搜索的代码更简短,到底用哪种方法就看个人喜好了。
数据问题 经过测试,这三个代码均只在AcWing 上通过了所有数据点,在PTA 和Online Judge 上均只通过了一个数据点,大概率是后面两个的测试数据有问题。
城堡问题-双重解法 空 梦 | 山岳库博
更新于 2022-04-11
发布于 2022-04-11