【USACO 5.1.2】Starry Night

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

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 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

庞大的模拟题。

八种情况让你写得手软,所以在此要好好利用学习过的技能(Ctrl + c).

写这种题之前,要仔细想清细节,不要盲目敲代码(这会使你打一段删一段,从而使你速度大减,并且有很大的机会出错,也就是要减少更改的次数)优化判断的速度。

最后就是敲代码啦。

找一个星座出来的方法就是用floodfill。暴力判重即可。

代码200+行。

/*
TASK:starry
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXM = 105;
const int d[2][8] = {{0, -1, -1, -1, 0, 1, 1, 1},
                     {-1, -1, 0, 1, 1, 1, 0, -1}};

struct Cluster
{
    char s[MAXM][MAXM];
    int numst, high, wide;

    bool operator == (const Cluster &b)
    {
        if (numst != b.numst) return false;

        if (high == b.high && wide == b.wide)
        {
            bool flag;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[i][j])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[high - i - 1][j])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[i][wide - j - 1])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[high - i - 1][wide - j - 1])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;
        }

        if (high == b.wide && wide == b.high)
        {
            bool flag;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[wide - j - 1][i])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[j][i])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[j][high - i - 1])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;

            for (int i = 0; i < high; ++i)
            {
                flag = true;
                for (int j = 0; j < wide; ++j)
                    if (s[i][j] != b.s[wide - j - 1][high - i - 1])
                    {
                        flag = false;
                        break;
                    }
                if (!flag) break;
            }
            if (flag) return true;

        }
        return false;
    }

}clusters[30];

char g[MAXM][MAXM];
int h, w, mark[MAXM * MAXM], num[MAXM][MAXM], cnt1, cnt2, left, right, up, down;
bool vis[MAXM][MAXM];

Cluster create()
{
    Cluster tmp;
    memset(tmp.s, 0, sizeof(tmp.s));
    tmp.numst = 0;
    tmp.high = down - up + 1;
    tmp.wide = right - left + 1;
    for (int i = 0; i < tmp.high; ++i)
        for (int j = 0; j < tmp.wide; ++j)
        {
            if (num[i + up][j + left] == cnt1) tmp.s[i][j] = ‘1‘, tmp.numst++;
            else tmp.s[i][j] = ‘0‘;
        }
    return tmp;
}

bool test(int x, int y)
{
    return 0 <= x && x < h && 0 <= y && y < w;
}

void floodfill(int x0, int y0)
{
    vis[x0][y0] = false;
    num[x0][y0] = cnt1;
    up = min(up, x0);
    down = max(down, x0);
    left = min(left, y0);
    right = max(right, y0);
    for (int i = 0; i < 8; ++i)
    {
        int x = x0 + d[0][i], y = y0 + d[1][i];
        if (test(x, y) && g[x][y] == ‘1‘ && vis[x][y]) floodfill(x, y);
    }
}

int main()
{
    freopen("starry.in", "r", stdin);
    freopen("starry.out", "w", stdout);
    scanf("%d%d", &w, &h);
    for (int i = 0; i < h; ++i) scanf("%s", g[i]);
    memset(vis, true, sizeof(vis));
    memset(num, 0, sizeof(num));
    cnt1 = cnt2 = 0;
    for (int i = 0; i < h; ++i)
        for (int j = 0; j < w; ++j)
            if (vis[i][j] && g[i][j] == ‘1‘)
            {
                ++cnt1;
                up = down = i;
                left = right = j;
                floodfill(i, j);
                Cluster cl = create();
                bool flag = true;
                for (int k = 0; k < cnt2; ++k)
                    if (cl == clusters[k])
                    {
                        mark[cnt1] = k;
                        flag = false;
                        break;
                    }
                if (flag) clusters[mark[cnt1] = cnt2++] = cl;
            }
    for (int i = 0; i < h; ++i)
    {
        for (int j = 0; j < w; ++j)
            if (g[i][j] != ‘0‘) printf("%c", mark[num[i][j]] + ‘a‘);
            else printf("0");
        printf("\n");
    }
    return 0;
}
时间: 2024-08-28 21:52:06

【USACO 5.1.2】Starry Night的相关文章

【USACO 1.3.4】牛式

[題目描述 ] 下面是一个乘法竖式,如果用我们给定的那n个数字来取代*,可以使式子成立的话,我们就叫这个式子牛式. * * * x * * ---------- * * * * * * ---------- * * * * 数字只能取代*,当然第一位不能为0,况且给定的数字里不包括0. 注意一下在美国的学校中教的"部分乘积",第一部分乘积是第二个数的个位和第一个数的积,第二部分乘积是第二个数的十位和第一个数的乘积. 写一个程序找出所有的牛式. [格式] INPUT FORMAT: (f

【USACO 1.2.2】方块转换

[问题描述] 一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案.写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式: 1:转90度:图案按顺时针转90度. 2:转180度:图案按顺时针转180度. 3:转270度:图案按顺时针转270度. 4:反射:图案在水平方向翻转(以中央铅垂线为中心形成原图案的镜像). 5:组合:图案在水平方向翻转,然后再按照1到3之间的一种再次转换. 6:不改变:原图案不改变. 7:无效转换:无法用以上方法得到新图案. 如

【USACO 2.3.4】货币系统

[描述] 母牛们不但创建了它们自己的政府而且选择了建立了自己的货币系统.由于它们特殊的思考方式,它们对货币的数值感到好奇. 传统地,一个货币系统是由1,5,10,20 或 25,50, 和 100的单位面值组成的. 母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值. 举例来说, 使用一个货币系统 {1,2,5,10,...}产生 18单位面值的一些可能的方法是:18x1, 9x2, 8x2+2x1, 3x5+2+1,等等其它. 写一个程序来计算有多少种方法用给定的货币系统来构

【USACO 2.3.3】零数列

[题目描述] 请考虑一个由1到N(N=3, 4, 5 ... 9)的数字组成的递增数列:1 2 3 ... N. 现在请在数列中插入“+”表示加,或者“-”表示减,“ ”表示空白(例如1-2 3就等于1-23),来将每一对数字组合在一起(请不要在第一个数字前插入符号). 计算该表达式的结果并判断其值是否为0. 请你写一个程序找出所有产生和为零的长度为N的数列. [格式] PROGRAM NAME: zerosum INPUT FORMAT 单独的一行表示整数N (3 <= N <= 9). O

【USACO 2.3.5】控制公司

[题目描述] 有些公司是其他公司的部分拥有者,因为他们获得了其他公司发行的股票的一部分.例如,福特公司拥有马自达公司12%的股票.据说,如果至少满足了以下三个条件之一,公司A就可以控制公司B了: 公司A = 公司B. 公司A拥有大于50%的公司B的股票. 公司A控制K(K >= 1)个公司,记为C1, ..., CK,每个公司Ci拥有xi%的公司B的股票,并且x1+ .... + xK > 50%. 给你一个表,每行包括三个数(i,j,p):表明公司i享有公司j的p%的股票.计算所有的数对(h

【USACO 1.4.2】时钟

[题目描述] 考虑将如此安排在一个 3 x 3 行列中的九个时钟: |-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| |-------| A B C |-------| |-------| |-------| | | | | | | | O | | O | | O | | | | | | | | | | |-------| |-------| |---

【USACO 1.4.1】铺放矩形块

[描述] 给定4个矩形块,找出一个最小的封闭矩形将这4个矩形块放入,但不得相互重叠.所谓最小矩形指该矩形面积最小. 所有4个矩形块的边都与封闭矩形的边相平行,图1示出了铺放4个矩形块的6种方案.这6种方案是仅可能的基本铺放方案.因为其它方案能由基本方案通过旋转和镜像反射得到. 可能存在满足条件且有着同样面积的各种不同的封闭矩形,你应该输出所有这些封闭矩形的边长. (分类注解:这里的分类依据可以视为是不同的面积计算公式.) [格式] INPUT FORMAT: (file packrec.in)

【USACO 1.2.1】挤牛奶

[问题描述] 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶.第一个农民在300时刻(从5点开始计时,秒为单位)给他的牛挤奶,一直到1000时刻.第二个农民在700时刻开始,在 1200时刻结束.第三个农民在1500时刻开始2100时刻结束.期间最长的至少有一个农民在挤奶的连续时间为900秒(从300时刻到1200时刻),而最长的无人挤奶的连续时间(从挤奶开始一直到挤奶结束)为300时刻(从1200时刻到1500时刻). 你的任务是编一个程序,读入一个有N个农民(1 <= N <= 5000

【USACO 3.1.5】联系

[描述] 奶牛们开始对用射电望远镜扫描牧场外的宇宙感兴趣.最近,他们注意到了一种非常奇怪的脉冲调制微波从星系的中央发射出来.他们希望知道电波是否是被某些地外生命发射出来的,还是仅仅是普通的的星星发出的. 帮助奶牛们用一个能够分析他们在文件中记下的记录的工具来找到真相.他们在寻找长度在A到B之间(含)在每天的数据文件中重复得最多的比特序列 (1 <= A <= B <= 12).他们在找那些重复得最多的比特序列.一个输入限制告诉你应输出多少频率最多的序列. 符合的序列可能会重叠,并且至少出