poj-1069(三角形和六边形)(转)

题意:

给你最多10种边长范围在1~25的正三角形,问能不能用它们拼成一个指定边长(指定的范围也是1~25)的正六边形(每种三角形使用的个数没有限制)。图1是一个用边长为23的三角形拼成边长为9的正六边形的例子。

 

具体代码:

//此题难再见坐标,其他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;
}
View Code

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值