HDU 2019 Multi-University Training Contest 8 杭电2019多校联合训练赛 第八场 1001 Acesrc and Cube Hypernet (6657)

Problem Description

Acesrc is fond of cube nets. If we cut some edges of a cube, the surface of the cube can be unfolded into 2-dimensional space, and the resulting flat shape is called a cube net. There are 11 essentially different cube nets, listed below.
在这里插入图片描述
In this problem, we consider a generalization of the cube net, called cube hypernet. For each face of a cube, we divide it into k×k small square cells. If we cut some edges of these small cells, the surface of the cube can be unfolded into 2-dimensional space, then the resulting flat shape is a cube hypernet. Clearly, cube nets are just a special type of cube hypernets where k=1. The following picture illustrates a cube hypernet and explains how it is formed.
在这里插入图片描述
Identifying cube nets is a relatively easy job; however, this might not be true for cube hypernets. Here comes the challenge. Given a flat shape composed of small squares, determine whether it is a cube hypernet.

Input

The first line of the input is a single integer T (1≤T≤30), denoting the number of test cases.
For each test case, the first line contains two integers h,w (1≤h,w≤100), denoting the height and width of the input region. Each of the remaining h lines contains w characters, either ‘#’ or ‘.’. The character ‘#’ means that the square is part of the shape, while ‘.’ not.
It is guaranteed that the input shape is nonempty and connected in four directions, and there is no hole inside the shape, not even a hole 8-connected to the outside. Also, the sum of h×w over all test cases does not exceed 35000.

Output

For each test case, output yes in a line if the input shape is cube hypernet, and no otherwise.

Sample Input

2
6 9
…##…
…##…
########.
.########
…##…
…##…
1 6

Sample Output

yes
no


题意

给定一个图,问能不能折成立方体。

思路

随机选取一个点,遍历这个点在某平面的位置,用dfs判断其他点是否符合条件,若整个平面都不符合,则无法折成立方体。
(其他直接看代码(其实就是标程),都写上注释了)

坑点

想不到


代码

#include<bits/stdc++.h>

#define F first
#define S second

using namespace std;

typedef pair<int,int> pi;

///定义方向向量
const int dx[4]= {1,0,-1,0};
const int dy[4]= {0,1,0,-1};

///数组第一维表示在哪个平面,第二维表示下个平面的方向,pair第一维表示下一个平面是哪个,第二维表示如何重置ii,jj
pi cov[6][4]={
{(pi){1,0},(pi){2,3},(pi){3,2},(pi){4,1}},
{(pi){5,0},(pi){2,0},(pi){0,0},(pi){4,0}},
{(pi){5,3},(pi){3,0},(pi){0,1},(pi){1,0}},
{(pi){5,2},(pi){4,0},(pi){0,2},(pi){2,0}},
{(pi){5,1},(pi){1,0},(pi){0,3},(pi){3,0}},
{(pi){3,2},(pi){2,1},(pi){1,0},(pi){4,3}}
};

char s[105][105];///储存原图
bool v[6][105][105];///记录某平面某点的vis状态--第一维 六个面  第二维第三维 在平面中的位置
bool vis[105][105];///记录原图中某点的vis状态
bool flag;///定义当前状态(初始点在某面中的位置)能否组成一个立方体
int n,m;///定义原图的大小
int k;///定义组成的立方体的边长
int cnt;///记录原图中#的个数,方便后续计算k
int px,py;///随机选取一个点作为起始点

///初始化数组
void init(int k)
{
    ///初始化v数组
    for (int p=0; p<6; p++)
        for (int i=1; i<=k; i++)
            for (int j=1; j<=k; j++)
                v[p][i][j]=0;

    ///初始化vis数组
    for (int i=0; i<n; i++)
        for (int j=0; j<m; j++)
            vis[i][j]=0;
}

///传送到下一个平面的对应位置
void _turn(int &x,int &y,int o)
{
    if (o==1)
    {
        swap(x,y);
        x=k+1-x;
    }
    else if (o==2)
    {
        x=k+1-x;
        y=k+1-y;
    }
    else if (o==3)
    {
        swap(x,y);
        y=k+1-y;
    }
}

///判断走到的点是否符合条件
bool valid(int x,int y)
{
    ///超出全图边界
    if (x<0||x>=n||y<0||y>=m)
        return 0;
    ///不是#
    if (vis[x][y]||s[x][y]!='#')
        return 0;
    ///符合条件
    return 1;
}

///x,y在原图中的坐标,p表示这个点在第几个平面,t保证不管从哪个方向进入建立的坐标系都相同,i,j表示在某平面的位置
void dfs(int x,int y,int p,int t,int i,int j)
{
    ///如果v[p][i][j]已经被访问过,则直接返回不符合条件
    if (v[p][i][j])
        flag=0;

    ///记录某平面某点已经走过
    v[p][i][j]=1;

    ///记录原图中的某点已经走过
    vis[x][y]=1;

    ///在原图中往四个方向走
    for (int o=0; o<4; o++)
    {
        ///判断该点在不在图中,以及该点是不是#,如果不是直接走下一个点
        if (!valid(x+dx[o],y+dy[o]))
            continue;

        ///计算该点在某平面上的新位置
        int ii=i+dx[(o+t)%4],jj=j+dy[(o+t)%4];

        ///判断是否还在该平面内
        if (ii>k)///走出边界
        {
            ///判断下一个平面--第一维表示原平面是哪个,第二维表示下一个平面的方向
            int rt=cov[p][0].S;

            ///减掉超出的部分,计算正确的平面位置
            ii-=k;

            ///更新到新平面的i,j
            _turn(ii,jj,rt);

            ///控制新的i j的位置,保证不管从哪个方向进入建立的坐标系都相同
            dfs(x+dx[o],y+dy[o],cov[p][0].F,(t+rt)%4,ii,jj);
        }
        else if (jj>k)///走出边界
        {
            int rt=cov[p][1].S;
            jj-=k;
            _turn(ii,jj,rt);
            dfs(x+dx[o],y+dy[o],cov[p][1].F,(t+rt)%4,ii,jj);
        }
        else if (ii<1)///走出边界
        {
            int rt=cov[p][2].S;
            ii+=k;
            _turn(ii,jj,rt);
            dfs(x+dx[o],y+dy[o],cov[p][2].F,(t+rt)%4,ii,jj);
        }
        else if (jj<1)///走出边界
        {
            int rt=cov[p][3].S;
            jj+=k;
            _turn(ii,jj,rt);
            dfs(x+dx[o],y+dy[o],cov[p][3].F,(t+rt)%4,ii,jj);
        }
        else///在该平面内
        {
            dfs(x+dx[o],y+dy[o],p,t,ii,jj);
        }
    }
}

bool check()
{
    ///遍历该点在立方体中某平面的位置
    for (int i=1; i<=k; i++)
    {
        for (int j=1; j<=k; j++)
        {
            ///初始化
            init(k);

            ///假设符合条件,之后DFS的时候如果有发现不满足条件的将flag设为0
            flag=1;

            ///DFS
            dfs(px,py,0,0,i,j);

            ///如果有一种情况符合条件,直接返回1(输出yes)
            if (flag)
                return 1;
        }
    }
    return 0;
}

char t[15][15];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        cnt=0;///记录图中#的个数
        for (int i=0; i<n; i++)
        {
            scanf("%s",s[i]);
            for (int j=0; j<m; j++)
            {
                if (s[i][j]=='#')
                {
                    ///px py记录一个#点在原图中的坐标,作为dfs的起始点
                    px=i;
                    py=j;

                    ///记录#的个数
                    cnt++;
                }
            }
        }

        ///求出边长
        k=(int)sqrt(cnt/6);

        ///判断#的个数能否组成立方体
        if (k*k*6!=cnt)
        {
            printf("no\n");
            continue;
        }

        if (check())
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}


发布了42 篇原创文章 · 获赞 6 · 访问量 4026

猜你喜欢

转载自blog.csdn.net/qq_43383246/article/details/99655966