POJ1111 Image Perimeters(求连块周长)

8 篇文章 0 订阅

</pre>题目描述<p></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; font-size:15.555556297302246px; line-height:35px">有一个矩形的由 X 和 . 组成的图像,已知它的长和宽。现在给你一个坐标(保证坐标上是X),求其整个连块的周长。(连块就是连着的X,斜着有相同顶点也算)。</p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; font-size:15.555556297302246px; line-height:35px">输入长,宽,坐标X,坐标Y,接着是图。</p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; font-size:15.555556297302246px; line-height:35px">多组数据,4个0结束。</p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; font-size:15.555556297302246px; line-height:35px">样例</p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; font-size:15.555556297302246px; line-height:35px">输入</p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; color:rgb(85,85,85); font-family:'microsoft yahei'; font-size:15.555556297302246px; line-height:35px"></p><pre class="sio" name="code" style="white-space: pre-wrap; word-wrap: break-word; color: rgb(85, 85, 85); line-height: 35px; background-color: rgb(255, 255, 255); font-family: 'Courier New', Courier, monospace; font-size: 14px;">7 7 4 4
XXXXXXX
XX...XX
X..X..X
X..X...
X..X..X
X.....X
XXXXXXX
0 0 0 0
有个思路较好:要注意到周长的定义!,求一个连块的周长即找边界即可,从x开始搜,搜到一个外界的块那么周长加1,且做标记,可以用映射也可以用改动标志。
<pre name="code" class="cpp">#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
char a[25][25];
int sx,sy;
int cx,ry,sum=0;
void dfs(int y,int x)
{
    a[y][x]='!';                 //改动标志来代替开一个数组加以映射。
    for(int i=-1;i<=1;i++)
        for(int j=-1;j<=1;j++){
            if(!i&&!j) continue;              //去掉i=0且j=0(不移动)这一情况
            if(a[y+i][x+j]=='X'&&1<=y+i&&y+i<=ry&&1<=x+j&&x+j<=cx)
            {
                dfs(y+i,x+j);
            }
            if((a[y+i][x+j]=='.'&&j==0)||(a[y+i][x+j]=='.'&&i==0)||(1>y+i&&j==0)||(y+i>ry&&j==0)||(x+j<1&&i==0)||(x+j>cx&&i==0))
            {

                sum++;                     //找到正左正右正上正下有边界,则周长加一
            }

        }
}
int main()
{
   while(cin>>ry>>cx>>sy>>sx&&ry)
   {
       sum=0;
        memset(a,0,sizeof(a));
       for(int i=1;i<=ry;i++)
            scanf("%s",a[i]+1);
        dfs(sy,sx);
        printf("%d\n",sum);
   }
    return 0;
}


 
微微的思路:从给定坐标指向的X块向“深处”搜索。要求整个连通块的周长,不难发现和连通块中每个X的四周其他X的数量有关。若一个X上,下,左,右四个方向一个X都没有(因为斜着有相同顶点也算是连通,所以有这种情况的)那么这个X块对周长的贡献就是4。若有四周1个X,那么贡献就是3。四周2个X贡献2,四周3个X贡献1。若是四周全都是X,那么就自然没有贡献咯。最后输出总贡献就是周长了。

 
<pre name="code" class="cpp">#include <cstdio>  
#include <cstring>  
const int maxn = 21;  
char pic[maxn][maxn];//图像  
int chek[maxn][maxn];//记录已经算过它周长的X块  
int ans = 0;//记录周长  
int chang,kuan;//图像的长宽  
int chck(int x,int y)//不要看我先去看main函数  
{  
    if(x<0 || y<0 || x>=chang || y>=kuan) return 0;//如果这一点出界,返回0  
    if(pic[x][y] == '.') return 0;//如果这一点是.返回0  
    return 1;//最后肯定留下在界内的X,所以返回1  
}  
void dfs(int x,int y)//不要看我先去看main函数  
{  
    if(x<0 || y<0 || x>=chang || y>=kuan) return;//如果出界,不考虑  
    if(pic[x][y] == '.' || chek[x][y] != 0) return;//如果它不是X,或者已经考虑过了,那么也不考虑  
    chek[x][y] = 1;//表示这一点已经考虑过了  
    int s = chck(x-1,y) + chck(x+1,y) + chck(x,y-1)+ chck(x,y+1);//chck函数是判断这一点是不是X,因为有可能出界,所以不要直接简单用if/*这里的check,可以综合一下,当初写check函数的时候就写成检查四个面是不是X的会更简便*/<span style="font-family: Consolas, 'Courier New', Courier, mono, serif;">  </span>
    if(s==3) ans+=1;//四周有3个X,贡献为1,下面同理  
    if(s==2) ans+=2;  
    if(s==1) ans+=3;  
    if(s==0) ans+=4;  
    dfs(x-1,y+1);//四面八方扫一遍  
    dfs(x-1,y);  
    dfs(x-1,y-1);  
    dfs(x,y-1);  
    dfs(x,y+1);  
    dfs(x+1,y+1);  
    dfs(x+1,y);  
    dfs(x+1,y-1);  
/*上面的四面八方扫一遍也可以用循环实现,更简洁。
}  
  
int main()  
{  
    while(scanf("%d%d",&chang,&kuan) &&chang&&kuan){//读入图像长和宽  
        memset(pic,0,sizeof(pic));  
        memset(chek,0,sizeof(chek));//切记切记初始化这里小心,因为一开始把初始化粗心放到while外面了WA了一发  
        ans = 0;//这也是初始化,周长置为0  
        int x,y;//坐标  
        scanf("%d%d",&x,&y);//读入坐标。注意这里实际指向的是pic[x-1][y-1]!  
        for(int i = 0 ;i < chang ; i ++) scanf("%s",pic[i]);//读入整张图  
        dfs(x-1,y-1);//DFS思想,通俗说就是以这一点为源头把这个连块的所有X块都给揪出来。  
        printf("%d\n",ans);//输出最后的周长  
    }  
    return 0;  
}  
注释真良心,感谢微微~
 

可见也可以用这种找规律的方法来写,找到周长的贡献度,不过这样会加大编写代码的思维难度。


当然也可以用BFS写 0ms:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
struct point
{
  int x;
  int y;
};
int col,row,sx,sy,ans=0;
bool book[25][25];
char a[25][25];
queue<point> que;
void ini()
{
    memset(book,0,sizeof(book));
    memset(a,0,sizeof(a));
    while(!que.empty()) que.pop();
    ans=0;
    cin>>sx>>sy;
    for(int i=1;i<=row;i++) scanf("%s",a[i]+1);

}
void bfs()
{
    point temp;
    temp.x=sx;
    temp.y=sy;
    book[sx][sy]=true;
    que.push(temp);
    while(que.size())
    {
        point temp=que.front();
        point next;
        for(int i=-1;i<=1;i++)
            for(int j=-1;j<=1;j++){
            if(!j&&!i) continue;
            next.x=temp.x+i;
            next.y=temp.y+j;
            if(book[next.x][next.y]) continue;
            if(!(i*j)&&(a[next.x][next.y]=='.'||next.x<1||next.x>row||next.y<1||next.y>col)) ans++;
            if(a[next.x][next.y]=='X') {
                que.push(next);
                book[next.x][next.y]=1;
            }
        }
        que.pop();
    }
}
int main()
{
 //   freopen("1.in","r",stdin);
    while(cin>>row>>col&&row)
    {
        ini();
        bfs();
        cout<<ans<<endl;
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值