题意:现在给定一个正六边形的边长,然后再给n种小正三角形,问能否用这n种小正三角形填满这个正六边形。小三角形可以不全用。每种小三角无限用。
思路:这题关键是建系,我是以60度角 以六边形左上角的边“ / ” 和下面的 " _ " 这条边建的系 也可以以120度角来建系 看自己习惯哪一种 然后我输出一下我建系后六边形是怎样表示的
边长为3的六边形:
000000011111
000000000111
000000000001
100000000000
111000000000
111110000000
注:(1)、每个0、1表示边长为一的小三角形 (六边形最基础的元素)
(2)、等边三角形映射到这个左边中即为直角三角形了 如下图则是表示边长为3的三角形 (正着和倒着)
0 00000
000 000
00000 0
然后就只要注意一些预处理和标记取消标记就好dfs了
预处理+剪枝
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 110 using namespace std; int n,m,flag,cnt; int a[15],b[15]; bool mp[maxn][maxn]; void showmap() // 中间输出函数 方便debug { int i,j; printf("\n"); for(i=1; i<=2*n; i++) { for(j=1; j<=4*n; j++) { printf("%d",mp[i][j]); } printf("\n"); } } void presolve() { int i,j; sort(a+1,a+m+1); cnt=0; for(i=1; i<=m; i++) { if(a[i]>=2*n) break; for(j=1; j<=cnt; j++) { if(a[i]%b[j]==0) break; } if(j==cnt+1) b[++cnt]=a[i]; } } void init() { int i,j,temp; memset(mp,1,sizeof(mp)); for(i=1; i<=n; i++) { temp=2*n+1+(i-1)*2; for(j=1; j<=temp; j++) { mp[i][j]=0; } } for(i=n+1; i<=2*n; i++) { for(j=4*n; j>1+(i-n-1)*2; j--) { mp[i][j]=0; } } } bool isok(int u,int v,int k) { int i,j; // printf("u:%d v:%d k:%d\n",u,v,k); if(v%2==0) { for(i=u+b[k]-1;i>=u;i--) { for(j=v+2*(b[k]-1);j>=v+2*(b[k]-1)-2*(b[k]+u-1-i);j--) { if(mp[i][j]) { // printf("i:%d j:%d\n",i,j); return false; } } } } else { for(i=u;i<u+b[k];i++) { for(j=v;j<v+1+2*(i-u);j++) { if(mp[i][j]) return false; } } } return true; } void mark(int u,int v,int k,int flag1) { int i,j; if(v%2==0) { for(i=u+b[k]-1;i>=u;i--) { for(j=v+2*(b[k]-1);j>=v+2*(b[k]-1)-2*(b[k]+u-1-i);j--) { if(flag1) mp[i][j]=1; else mp[i][j]=0; } } } else { for(i=u;i<u+b[k];i++) { for(j=v;j<v+1+2*(i-u);j++) { if(flag1) mp[i][j]=1; else mp[i][j]=0; } } } } void dfs(int x,int y) { int i,j; if(flag) return ; // showmap(); // printf("x:%d y:%d\n",x,y); if(x==2*n&&y>4*n||x>2*n) { flag=1; return ; } if(y>4*n) dfs(x+1,1); else if(mp[x][y]) // 加上else 不然会死循环 想一想 为什么 { for(j=y+1; j<=4*n; j++) { if(mp[x][j]==0) break; } dfs(x,j); } else { for(i=1; i<=cnt; i++) { if(isok(x,y,i)) { mark(x,y,i,1); // 标记 dfs(x,y+1); mark(x,y,i,0); // 取消标记 } else break; } } } int main() { int i,j,t; scanf("%d",&t); while(t--) { flag=0; scanf("%d%d",&n,&m); for(i=1; i<=m; i++) { scanf("%d",&a[i]); if(n%a[i]==0) flag=1; } if(flag) printf("YES\n"); // 预处理 三角形的边长是六边形约数则一定满足条件 else { presolve(); // 预处理 init(); showmap(); dfs(1,1); if(flag) printf("YES\n"); else printf("NO\n"); } } }