传送门:HDU5113
本以为这么小的数据量可以不用剪枝,然而事实证明我还是多想了。。关键剪枝为:
当某种颜色的剩余数量大于剩余格子数的一半时,直接返回,因为这种情况继续搜下去无论怎么涂色必定有两个相邻的同色,请自行证明。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
using namespace std;
int time[30];
int n,m,k,flag=0,num;
int map[7][7];
void dfs(int r,int c)
{
if(r>n||c>m||flag)
return ;
double t;
t=n*m-((r-1)*m+c-1);
//printf("%lf",ceil(t/2.0));
for(int i=1;i<=k;i++)//关键剪枝
if(time[i]>ceil(t/2))
return ;
for(int i=1;i<=k;i++)
{
if(time[i]>0&&map[r-1][c]!=i&&map[r][c-1]!=i)
{
time[i]--;
map[r][c]=i;
if(r==n&&c==m)
{
flag=1;
return ;
}
if(c==m)
dfs(r+1,1);
else
dfs(r,c+1);
if(flag)
return ;
//map[r][c]=0;
time[i]++;
}
}
}
int main()
{
int t;
scanf("%d",&t);
for(int s=1;s<=t;s++)
{
scanf("%d%d%d",&n,&m,&k);
flag=0;
//num=k;
memset(map,0,sizeof(map));
for(int i=1;i<=k;i++)
{
scanf("%d",&time[i]);
}
printf("Case #%d:\n",s);
dfs(1,1);
if(flag)
{
printf("YES\n");
for(int i=1;i<=n;i++)
{
printf("%d",map[i][1]);
for(int j=2;j<=m;j++)
printf(" %d",map[i][j]);
printf("\n");
}
}
else
printf("NO\n");
}
return 0;
}