• 解题报告 物理(即 usaco 5.1.2)


    3、美丽的星空(physics)(即 usaco  5.1.2)

    问题描述

    有一天,物理老师递给dsqwwe一张纸,神秘的说:”你要是把这个做出来,以后就不用交积累本了,否则,每天都交”,dsqwwe一阵狂喜,看都没看就答应了。仔细研究后才发现,物理老师的阴谋,但好几周未写积累本的他不能失败,于是,他想让你帮他编个程序。纸上的难题是这样的:

    这张纸上画了一个n*m的星空图,当然,图中有许多的星座。一个星座是指一群连通的星组成的非空集合,所谓连通是指水平,垂直或者对角相邻。一个星座不能是另一个更大星座的一部分, 星座可以相似(similar)。如果两个星座有相同的形状,而且包括相同数目的星体,那么不管其方向性如何,就算相似。一般而言,星座可能的方向有八个,如图所示

     

    纸上的天体图是一个由字符0和1组成的二维矩阵,字符1表示所在的位置有一颗星;字符0表示该位置上没有星.给定一份天体图,用同一个小写英文标识相似的所有星座。相似的星座必须用相同的字母标识,不同的星座表示为不同的字母。标识一个星座,就是将其中各星体对应的字符1替换为相应的小写字母。

    输入文件

    文件的前两行分别记录了天体图的宽度m、深度n。而天体图则是由接下来的n行表示,每行包括m个字符

    输出文件

    输出文件记录了天体图与输入相似,不同之处在于,各个星座按照“任务”中的要求进行了标识。 对于同一个输入文件,可能会有很多不同的标识,此时,输出字典序最小的标识。

    样例输入

    23

    15

    10001000000000010000000

    01111100011111000101101

    01000000010001000111111

    00000000010101000101111

    00000111010001000000000

    00001001011111000000000

    10000001000000000000000

    00101000000111110010000

    00001000000100010011111

    00000001110101010100010

    00000100110100010000000

    00010001110111110000000

    00100001110000000100000

    00001000100001000100101

    00000001110001000111000

    样例输出

    a000a0000000000b0000000

    0aaaaa000ccccc000d0dd0d

    0a0000000c000c000dddddd

    000000000c0b0c000d0dddd

    00000eee0c000c000000000

    0000e00e0ccccc000000000

    b000000e000000000000000

    00b0f000000ccccc00a0000

    0000f000000c000c00aaaaa

    0000000ddd0c0b0c0a000a0

    00000b00dd0c000c0000000

    000g000ddd0ccccc0000000

    00g0000ddd0000000e00000

    0000b000d0000f000e00e0b

    0000000ddd000f000eee000

    数据范围

    0 <= m <= 100

    0 <=n <= 100

    0 <= 星座的数目 <= 500

    0 <= 不相似的星座数目 <= 26 (a..z)

    1 <= 各星座包含的星体数目 <= 160

    Hint

    样例输出

     

     

     

    Liukeke 的学科试题之三·物理。

     

    这道题跟物理这个学科一样的恶心。

     

    Floodfill + 模拟判重。

     

    前面那个就不说了。

     

    判重有两种方法:

    记录他的左上和右下坐标,将他从图上摘下来,旋转 次,判断。(代码会编到死)

    写两个旋转过程,左旋和镜面对称,左旋一次,镜面一次。。。。(同上)

    然后,比较好的是,注意每一个不相同的图形,它的图形中,任意两点之间的距离之和,如果用实数存的话,他就是唯一的。然后 floodfill 的时候,记录一下它有哪些坐标,然后求出它任意两点之间的距离之和,存储,然后每次计算,直接判断。

     

    代码(Liukeke

    {
    ID: liukeke
    PROG: starry
    LANG: PASCAL
    }
    program liukeke;
    var
    a:array[0..101,0..101] of 0..1;
    c:array[0..101,0..101] of longint;
    v:array[0..101,0..101] of boolean;
    sum1,tmpx,tmpy:array[0..10000] of longint;
    sum2:array[0..10000] of double;
    name1:array[0..10000] of char;
    d:array[1..8,1..2] of longint=((1,0),(-1,0),(0,1),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1));
    n,m,tot,tt:longint;

    procedure init;
    var
    i,j:longint;
    ch:char;
    begin
    readln(m);
    readln(n);
    for i:=1 to n do
    begin
    for j:=1 to m do
    begin
    read(ch);
    if ch='0' then a[i,j]:=0 else a[i,j]:=1;
    end;
    readln;
    end;
    end;

    procedure dfs(x,y:longint);
    var
    i:longint;
    xx,yy:longint;
    begin
    inc(tt);
    tmpx[tt]:=x;
    tmpy[tt]:=y;
    for i:=1 to 8 do
    begin
    xx:=x+d[i,1];
    yy:=y+d[i,2];
    if (xx<1)or(yy<1)or(xx>n)or(yy>m)then continue;
    if v[xx,yy] then continue;
    if a[xx,yy]=0 then continue;
    v[xx,yy]:=true;
    dfs(xx,yy);
    end;
    end;

    procedure main;
    var
    i,j,a1,a2,k:longint;
    s:double;
    flag:boolean;
    begin
    for i:=1 to n do
    for j:=1 to m do
    if (not v[i,j])and(a[i,j]=1) then
    begin
    tt:=0;
    s:=0;
    flag:=false;
    v[i,j]:=true;
    dfs(i,j);
    for a1:=1 to tt do
    for a2:=1 to tt do
    s:=s+sqrt(sqr(tmpx[a1]-tmpx[a2])+sqr(tmpy[a1]-tmpy[a2]));
    for k:=1 to tot do
    if (sum1[k]=tt)and(abs(sum2[k]-s)<0.000001) then
    begin
    for a1:=1 to tt do
    c[tmpx[a1],tmpy[a1]]:=k;
    flag:=true;
    break;
    end;
    if not flag then
    begin
    inc(tot);
    sum1[tot]:=tt;
    sum2[tot]:=s;
    for a1:=1 to tt do
    c[tmpx[a1],tmpy[a1]]:=tot;
    end;
    end;
    end;

    procedure outit;
    var
    i,j:longint;
    now:longint;
    begin
    for i:=1 to tot do
    name1[i]:='1';
    now:=96;
    for i:=1 to n do
    for j:=1 to m do
    if a[i,j]=1 then
    if name1[c[i,j]]='1' then
    begin
    inc(now);
    name1[c[i,j]]:=chr(now);
    end;
    for i:=1 to n do
    begin
    for j:=1 to m do
    if a[i,j]=0 then
    write(0)
    else write(name1[c[i,j]]);
    writeln;
    end;
    end;

    begin
    assign(input,'physics.in');reset(input);
    assign(output,'physics.out');rewrite(output);
    init;
    main;
    outit;
    close(input);
    close(output);
    end.

  • 相关阅读:
    Java 线程
    杂记
    字符流分类详细介绍和各种字符流类介绍与使用 字符集
    内部类 与 匿名内部类
    Java IO流学习总结
    java的集合框架
    jquery 只能投票一次
    C# 简易版的计算器程序
    常用DBHelper类
    jQuery异步提交
  • 原文地址:https://www.cnblogs.com/SueMiller/p/2223930.html
Copyright © 2020-2023  润新知