POJ1069 The Bermuda Triangle DFS

这个坐标系建的真牛。。。。。。比赛碰到这种题目,必跪。。。。。。

见坐标是给每一个单位三角分配,不是一个点分配。

有两种建立方法,我用了夹角120方法。。。。。都一样的。。。

The Bermuda Triangle
Time Limit: 2000MS Memory Limit: 32768K
Total Submissions: 1096 Accepted: 509

Description

People in the hidden region of the Bermuda Triangle make everything they need in triangular shapes. One day, someone decided to break the rule and bake a hexagonally shaped cake. But as usual, he has to serve the cake in triangular pieces. The pieces are equilateral triangles but in different sizes for different people. He can use as many triangles as needed to cut the cake into pieces, such that nothing remains from the cake. For example, the following figure shows one way that a hexagon with side 9 can be cut into triangles with side 2 and 3. (The cake is cut along the thick lines, thin lines are drawn to show the sizes). 

Input is a hexagon and triangle types (specified by the length of their sides) and the goal is to decide if the hexagon can be completely divided by the given triangle types.

Input

The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. Each test case consists of a single line, containing s (1 <= s <= 25), the length of the hexagon's side, followed by n, the number of triangle types (1 <= n <= 10), followed by n integers representing the length of each triangle type's side (between 1 and 25, inclusive).

Output

There should be one output line per test case containing either YES or NO depending on whether the hexagon can be completely divided by the given triangle types.

Sample Input

3
5 2 2 3
7 2 3 2
13 2 2 3

Sample Output

NO
NO
YES



//此题难再见坐标,其他OK。。
//dfs用小正三角覆盖大正三角,问能否完全覆盖
//120坐标系建立
//画图自己研究。。。。。。、
//逐行DFS,填完一行在下一行。从下往上 从左往右
//一个三角一个三角覆盖
//判断能够覆盖的时候,小三角不行大三角一定不行
//背包优化。。这里没用 , 还有一种剪枝也没用 就是先判断1/2 1/3 1/6的覆盖。。。
//a[i]%a[j]==0就不要a[i]了;
//注意如果sz%a[i]==0 那么直接可以了。。。。
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>

using namespace std;

#define MAXN 110

int sz,a[15],n,tp;
int g[MAXN][MAXN];



bool jud1()
{
   for(int i=0;i<tp;i++)
        if(sz%a[i]==0) return true;
   return false;
}

//120度建立坐标
//横向扩大2 纵向不便,具体理解自己画图
void init()
{
    memset(g,0,sizeof(g));
    for(int i=1;i<=sz;i++)
        for(int j=1;j<=sz*2+2*i-1;j++)
            g[i][j]=1;
    for(int i=sz+1;i<=sz*2;i++)
        for(int j=(i-sz)*2;j<=sz*4;j++)
            g[i][j]=1;

}

bool judSZ(int x,int y,int size)
{
    if(y+2*size-2>sz*4 || x+size-1>sz*2) return false;
    if(y%2==1) //倒三角 规律自己画图看注意列坐标
    {
        for(int i=0;i<size;i++)
            for(int j=0;j<2*i+1;j++)
                if(!g[x+i][y+j]) return false;
    }
    else  //正三角
    {
        for(int i=0;i<size;i++)
            for(int j=2*i;j<2*size-1;j++)
                if(!g[x+i][y+j]) return false;
    }
    return true;
}

//覆盖回复和上面检查能否覆盖一样
void cover(int x,int y,int size)
{
    if(y%2==1)
    {
        for(int i=0;i<size;i++)
            for(int j=0;j<2*i+1;j++)
                g[x+i][y+j]=0;
    }
    else
    {
        for(int i=0;i<size;i++)
            for(int j=2*i;j<2*size-1;j++)
                g[x+i][y+j]=0;
    }
}

void remove(int x,int y,int size)
{
    if (y%2==1)
    {
        for(int i=0;i<size;i++)
            for(int j=0;j<2*i+1;j++)
                g[x+i][y+j]=1;
    }
    else
    {
        for(int i=0;i<size;i++)
            for(int j=2*i;j<2*size-1;j++)
                g[x+i][y+j]=1;
    }
}

bool dfs(int x,int y)
{
    if(x>sz*2) return true;
    if(y>sz*4) return dfs(x+1,1);
    if(!g[x][y])
    {
        int j;
        for(j=y+1;y<=4*sz;y++)
            if(g[x][j]) break;
        return dfs(x,j);
    }
    for(int i=0;i<tp;i++)
    {
        if(judSZ(x,y,a[i]))
        {
            cover(x,y,a[i]);
            if(dfs(x,y+1)) return true;
            remove(x,y,a[i]);
        }
        else
            break;
    }
    return false;
}

int main()
{
    int cs;
    cin>>cs;
    while(cs--)
    {
        cin>>sz;
        cin>>n;
        tp=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[tp++]);
           // if(a[tp]<=sz) tp++;
        }
        for(int i=0;i<tp;i++)
            for(int j=0;j<tp;j++)
            {
                if(i==j) continue;
                if(a[i]%a[j]==0)
                {
                    swap(a[i],a[tp-1]);
                    i--,tp--;
                    break;
                }
            }
        sort(a,a+tp);
        if(jud1())
        {
            printf("YES\n");
            continue;
        }
        init();
        if(dfs(1,1)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值