2018年实训周作业——图_POJ 1111 A - Image Perimeters

10 篇文章 0 订阅
6 篇文章 0 订阅

原题链接http://poj.org/problem?id=1111

Image Perimeters

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 9820 Accepted: 5714
Description

Technicians in a pathology lab analyze digitized images of slides. Objects on a slide are selected for analysis by a mouse click on the object. The perimeter of the boundary of an object is one useful measure. Your task is to determine this perimeter for selected objects.

The digitized slides will be represented by a rectangular grid of periods, ‘.’, indicating empty space, and the capital letter ‘X’, indicating part of an object. Simple examples are

XX Grid 1 .XXX Grid 2

XX .XXX

              .XXX 

              ...X 

              ..X. 

              X... 

An X in a grid square indicates that the entire grid square, including its boundaries, lies in some object. The X in the center of the grid below is adjacent to the X in any of the 8 positions around it. The grid squares for any two adjacent X’s overlap on an edge or corner, so they are connected.

XXX

XXX Central X and adjacent X’s

XXX

An object consists of the grid squares of all X’s that can be linked to one another through a sequence of adjacent X’s. In Grid 1, the whole grid is filled by one object. In Grid 2 there are two objects. One object contains only the lower left grid square. The remaining X’s belong to the other object.

The technician will always click on an X, selecting the object containing that X. The coordinates of the click are recorded. Rows and columns are numbered starting from 1 in the upper left hand corner. The technician could select the object in Grid 1 by clicking on row 2 and column 2. The larger object in Grid 2 could be selected by clicking on row 2, column 3. The click could not be on row 4, column 3.

One useful statistic is the perimeter of the object. Assume each X corresponds to a square one unit on each side. Hence the object in Grid 1 has perimeter 8 (2 on each of four sides). The perimeter for the larger object in Grid 2 is illustrated in the figure at the left. The length is 18.

Objects will not contain any totally enclosed holes, so the leftmost grid patterns shown below could NOT appear. The variations on the right could appear:

Impossible Possible

XXXX XXXX XXXX XXXX

X…X XXXX X… X…

XX.X XXXX XX.X XX.X

XXXX XXXX XXXX XX.X

… … … …

…X… …X… …X… …X…

.X.X. .XXX. .X… …

…X… …X… …X… …X…

… … … …
Input

The input will contain one or more grids. Each grid is preceded by a line containing the number of rows and columns in the grid and the row and column of the mouse click. All numbers are in the range 1-20. The rows of the grid follow, starting on the next line, consisting of ‘.’ and ‘X’ characters.

The end of the input is indicated by a line containing four zeros. The numbers on any one line are separated by blanks. The grid rows contain no blanks.
Output

For each grid in the input, the output contains a single line with the perimeter of the specified object.
Sample Input

2 2 2 2
XX
XX
6 4 2 3
.XXX
.XXX
.XXX
…X
…X.
X…
5 6 1 3
.XXXX.
X…X
…XX.X
.X…X
…XXX.
7 7 2 6
XXXXXXX
XX…XX
X…X…X
X…X…
X…X…X
X…X
XXXXXXX
7 7 4 4
XXXXXXX
XX…XX
X…X…X
X…X…
X…X…X
X…X
XXXXXXX
0 0 0 0
Sample Output

8
18
40
48
8
Source

Mid-Central USA 2001

题解:题意其实是求最大连通块的周长,对于一个X来说,它的周围八个方向都是连通的,它的周围可能是X,也可能是点,这个题要求的就是最大连通的多边形的周长,多边形中必须都是X。这个题既可以用DFS,也可以用BFS,不同的地方在于BFS(广度优先搜索)更快一些。
如果是用DFS ,那么对于每一个X进行深搜,注意访问过的点进行标记,如果深搜到的当前的X的水平垂直方向有点,那么周长加1,一直到搜完所有的点。至于为什么只有水平垂直方向加周长呢?是因为对于每一个X,如果它是所求连通块的边界,那么只需要考虑它的水平垂直方向有没有点,四个对角方向只是判断是否连通,所以在对于对角方向搜的时候不需要加周长。
如果是用BFS,思想是一样的,只是如果广度优先搜索,那么我就先把当前的所有跟X连通的点放进对列,每次出队的话就判断一下是否有点,水平垂直方向有点就加1。

我的代码:(DFS)

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

typedef struct node{
    int x,y;
}Pos_node;

char s[30][30];      //网格使用字符串表示
int rows,cols;       //网格的行列数
int total;           //选中目标的周长
int click_x,click_y; //鼠标单击的坐标

int diagonal[4][2] = {{1,1},{-1,1},{-1,-1},{1,-1}};
//对角线方向的坐标增量——右下、右上、左上、左下

int x_y[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
//水平垂直方向的坐标增量——下、右、上、左

int vis[30][30];
//其初值为0,每统计一个X,就将其坐标对应的单元置1

//(x,y)是当前的搜索坐标
int dfs(int x,int y)
{
    int i;
    int newx,newy;   //新的搜索坐标
    vis[x][y] = 1;   //标记为搜索
    for(i=0;i<4;i++) //搜索水平垂直方向
    {
        newx = x + x_y[i][0];
        newy = y + x_y[i][1];
        if((s[newx][newy]=='X') && (vis[newx][newy]==0)) //该坐标处是X,而且之前未被访问过
        {
            dfs(newx,newy);           //从这个点开始深搜,继续找下一个点
        }
        else if(s[newx][newy]=='.')   //根据周围点的贡献来计算最大连通块的周长
            total++;                  //累加边界上的网格单元
    }
    for(i=0;i<4;i++)                  //搜索对角线方向,需要注意的是,对角线方向的不需要加周长
    {
        newx = x + diagonal[i][0];
        newy = y + diagonal[i][1];
        if((s[newx][newy]=='X') && (vis[newx][newy]==0))
        {
            dfs(newx,newy);
        }
    }
    //递归结束的条件是所有的点均已被访问过,vis控制结束
}

//主函数
int main()
{
    while(cin>>rows>>cols>>click_x>>click_y)
    {
        memset(s,'.',sizeof(s));    //memset函数只能是单个字节的填充
        //将图像的边界扩展一圈'.',图像左上角的坐标不是从(0,0)开始,而是从(1,1)开始的
        if(rows == 0 && cols == 0 && click_x == 0 && click_y == 0)
            break;
        total = 0;
        memset(vis,0,sizeof(vis));   //标记清零
        vis[click_x][click_y] = 1;
        //char image[40];
        //注意行列号从1开始,构造网络
        for(int i=1;i<=rows;i++)
        {
            for(int j=1;j<=cols;j++)
                cin>>s[i][j];
        }
        if(s[click_x][click_y]=='.')
        total = 0;
        else
        dfs(click_x,click_y);
        cout<<total<<endl;
    }

}

大佬的BFS

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
typedef struct node
{
	int x, y;
}NODE;
int dir8[8][2] = { {0,1},{0,-1},{1,0},{-1,0},{1,-1},{1,1},{-1,-1},{-1,1} };
int dir4[4][2] = { {-1,0},{1,0},{0,1},{0,-1} };
int dis;
char map[30][30];
int vis[30][30];
int n, m, x, y;
void bfs(int x, int y)
{
	if (map[x][y] == '.') dis = 0;
	else {
		queue<NODE> q;
		NODE t;
		t.x = x;
		t.y = y;
		q.push(t);
		while (!q.empty()) {
			int tx, ty;
			NODE p = q.front();
			q.pop();
			for (int i = 0; i < 4; i++) {
				int a, b;
				a = p.x + dir4[i][0];
				b = p.y + dir4[i][1];
				if (map[a][b] == '.') dis += 1;
			}
			tx = p.x; ty = p.y;
			vis[tx][ty] = 1;
			for (int i = 0; i < 8; i++) {
				int ttx, tty;
				ttx = tx + dir8[i][0];
				tty = ty + dir8[i][1];
				if (map[ttx][tty] == 'X' && vis[ttx][tty] == 0) {
					vis[ttx][tty] = 1;
					p.x = ttx;
					p.y = tty;
					q.push(p);
				}
			}
		}
	}
}
int main()
{
	while (cin >> n >> m >> x >> y) {
		if (n == 0 && m == 0 && x == 0 && y == 0) break;
		for (int i = 0; i <= n + 1; i++) {
			for (int j = 0; j <= m + 1; j++) {
				map[i][j] = '.';
			}
		}
		memset(vis, 0, sizeof(vis));
		dis = 0;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				cin >> map[i][j];
			}
		}
		bfs(x, y);
		cout << dis << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值