usaco 5.1 Starry Night(BFS+枚举)

Starry Night
IOI 98

High up in the night sky, the shining stars appear in clusters of various shapes. A cluster is a non-empty group of neighbouring stars, adjacent in horizontal, vertical or diagonal direction. A cluster cannot be a part of a larger cluster.

Clusters may be similar. Two clusters are similar if they have the same shape and number of stars, irrespective of their orientation. In general, the number of possible orientations for a cluster is eight, as Figure 1 exemplifies.

Figure 1. Eight similar clusters 
Figure 1. Eight similar clusters

The night sky is represented by a sky map, which is a two-dimensional matrix of 0's and 1's. A cell contains the digit 1 if it has a star, and the digit 0 otherwise.

Given a sky map, mark all the clusters with lower case letters. Similar clusters must be marked with the same letter; non-similar clusters must be marked with different letters.

You mark a cluster with a lower case letter by replacing every 1 in the cluster by that lower case letter.

PROGRAM NAME: starry

INPUT FORMAT

The first two lines contain, respectively, the width W and the height H of a sky map. The sky map is given in the following H lines, of W characters each.

SAMPLE INPUT (file starry.in)

23
15
10001000000000010000000
01111100011111000101101
01000000010001000111111
00000000010101000101111
00000111010001000000000
00001001011111000000000
10000001000000000000000
00101000000111110010000
00001000000100010011111
00000001110101010100010
00000100110100010000000
00010001110111110000000
00100001110000000100000
00001000100001000100101
00000001110001000111000
In this case, the sky map has width 23 and height 15. Just to make it clearer, notice that this input file corresponds to the following picture of the sky.

Figure 2. Picture of thesky
Figure 2. Picture of the sky

OUTPUT FORMAT

The output file contains the same map as the input file, except that the clusters are marked as described in Task.

There will generally be more than one way to label the clusters with letters. Your program should choose the labeling such that if the entire output file is read as a string, this string will be minimal in the lexicographical ordering.

SAMPLE OUTPUT (file starry.out)

a000a0000000000b0000000
0aaaaa000ccccc000d0dd0d
0a0000000c000c000dddddd
000000000c0b0c000d0dddd
00000eee0c000c000000000
0000e00e0ccccc000000000
b000000e000000000000000
00b0f000000ccccc00a0000
0000f000000c000c00aaaaa
0000000ddd0c0b0c0a000a0
00000b00dd0c000c0000000
000g000ddd0ccccc0000000
00g0000ddd0000000e00000
0000b000d0000f000e00e0b
0000000ddd000f000eee000
This is one possible result for the sample input above. Notice that this output file corresponds to the following picture.


Figure 3. Picture with the clusters marked

Constraints

0 <=  W  (width of the sky map) <= 100
0 <=  H  (height of the sky map) <= 100
0 <= Number of clusters <= 500
0 <= Number of non-similar clusters <= 26 (a..z)

1 <= Number of stars per cluster <= 160

题意:给你一张图,0表示没有星星,1表示有星星,要求你找出所有星系(星系指相邻的星星构成的),结构相同的星系标上相同的字母。。。。

分析:首先用BFS给每个星系涂色,记录每个星系的坐标范围,接着枚举两个星系,判断是否是相同结构的,具体还是枚举其中一个星系的八个方向。。。

PS:这是道麻烦的题,除了调试困难,基本没啥问题,话说这种题我做得好慢啊,不过一般都是1Y的。。。

代码:

/*
ID: 15114582
PROG: starry
LANG: C++
*/
#include<cstdio>
#include<iostream>
using namespace std;
const int mm=555;
struct star
{
    int l,r,b,t,w,h;
}g[mm];
int dx[]={0,0,-1,1,-1,-1,1,1};
int dy[]={-1,1,0,0,-1,1,-1,1};
int sky[mm][mm],a[mm][mm],b[mm][mm];
int qx[mm],qy[mm],f[mm];
int n,m,r;
char s[mm];
void bfs(int x,int y,int t)
{
    int i,l,r=1;
    qx[0]=x,qy[0]=y,sky[x][y]=t;
    g[t].l=g[t].r=y,g[t].t=g[t].b=x;
    for(l=0;l<r;++l)
        for(i=0;i<8;++i)
        {
            x=qx[l]+dx[i];
            y=qy[l]+dy[i];
            if(x<1||x>n||y<1||y>m||sky[x][y])continue;
            qx[r]=x,qy[r]=y,sky[x][y]=t,++r;
            g[t].l=min(g[t].l,y);
            g[t].r=max(g[t].r,y);
            g[t].t=min(g[t].t,x);
            g[t].b=max(g[t].b,x);
        }
    g[t].w=g[t].r-g[t].l+1;
    g[t].h=g[t].b-g[t].t+1;
}
bool test(int w,int h)
{
    for(int i=1;i<=h;++i)
        for(int j=1;j<=w;++j)
            if(a[i][j]!=b[i][j])return 0;
    return 1;
}
bool same(int w,int h)
{
    int i,j;
    if(test(w,h))return 1;
    for(i=1;i<=h;++i)
        for(j=1;j<=w>>1;++j)
            swap(b[i][j],b[i][w-j+1]);
    if(test(w,h))return 1;
    for(j=1;j<=w;++j)
        for(i=1;i<=h>>1;++i)
            swap(b[i][j],b[h-i+1][j]);
    if(test(w,h))return 1;
    for(i=1;i<=h;++i)
        for(j=1;j<=w>>1;++j)
            swap(b[i][j],b[i][w-j+1]);
    return test(w,h);
}
bool check(int u,int v)
{
    if((g[u].w!=g[v].w||g[u].h!=g[v].h)
       &&(g[u].h!=g[v].w||g[u].w!=g[v].h))return 0;
    int i,j,wa=g[u].w,ha=g[u].h,wb=g[v].w,hb=g[v].h;
    for(i=g[u].t;i<=g[u].b;++i)
        for(j=g[u].l;j<=g[u].r;++j)
            a[i-g[u].t+1][j-g[u].l+1]=(sky[i][j]==u);
    for(i=g[v].t;i<=g[v].b;++i)
        for(j=g[v].l;j<=g[v].r;++j)
            b[i-g[v].t+1][j-g[v].l+1]=(sky[i][j]==v);
    if(wa==wb&&ha==hb&&same(wa,ha))return 1;
    for(i=1;i<=max(wb,hb);++i)
        for(j=1;j<i;++j)swap(b[i][j],b[j][i]);
    swap(wb,hb);
    if(wa==wb&&ha==hb&&same(wa,ha))return 1;
    return 0;
}
int find(int x)
{
    if(x!=f[x])f[x]=find(f[x]);
    return f[x];
}
int main()
{
    freopen("starry.in","r",stdin);
    freopen("starry.out","w",stdout);
    int i,j;
    while(~scanf("%d%d",&m,&n))
    {
        for(i=1;i<=n;++i)
            for(scanf("%s",s),j=0;j<m;++j)
                sky[i][j+1]=(s[j]=='1')-1;
        for(r=i=1;i<=n;++i)
            for(j=1;j<=m;++j)
                if(!sky[i][j])bfs(i,j,r++);
        for(i=1;i<r;++i)f[i]=i;
        for(i=1;i<r;++i)
            for(j=1;j<i;++j)
                if(check(i,j))f[find(i)]=find(j);
        for(j=0,i=1;i<r;++i)
            if(i==find(i))s[i]='a'+j++;
        for(i=1;i<=n;puts(""),++i)
            for(j=1;j<=m;++j)
                printf("%c",sky[i][j]<0?'0':s[find(sky[i][j])]);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值