这题肝了一个晚上,明明是回溯专题,类型也是回溯,最后回溯解法写出来了,也尽力优化了,一直TLE,最后题解是DP,好气啊!DP解法我在想想。
LL cnt=0;
int n,k;
int flag_45[20],flag_135[20];
void solve(int prev_s,int remain,int n){
if(remain==0){
cnt++;
return ;
}
for(int s=prev_s+1;s<=2*n-1-remain;s++){
for(int i=0;i<n;i++){
int j=s-i;
if(j>=0&&j<n&&!flag_45[i+j]&&!flag_135[n-1+j-i]){
flag_45[i+j]=flag_135[n-1+j-i]=1;
solve(s,remain-1,n);
flag_45[i+j]=flag_135[n-1+j-i]=0;
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&k),n+k){
cnt=0;
FILL(flag_45,0);
FILL(flag_135,0);
solve(-1,k,n);
printf("%lld\n",cnt);
}
return 0;
}
一个小时后,跑步时,想到 打表 打表 打表 我太聪明了,查询的总数很少,直接交超时,但本机跑出所有答案也不过10s,下面是打表结果:
1,1,
1,4,4,0,0,
1,9,26,26,8,0,0,0,0,0,
1,16,92,232,260,112,16,0,0,0,0,0,0,0,0,0,0,
1,25,240,1124,2728,3368,1960,440,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,36,520,3896,16428,39680,53744,38368,12944,1600,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,49,994,10894,70792,282248,692320,1022320,867328,389312,81184,5792,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,64,1736,26192,242856,1444928,5599888,14082528,22522960,22057472,12448832,3672448,489536,20224,256,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
直接开数组存好,O(1)输出就完事了,可见回溯解法弄出来了,超时也莫慌,一般数据量小的时候,在本机离线跑一遍,把结果存好输出,这真的是一个好方法,此时我想说,暴力算个啥,打表出奇迹,真开心。
下面是混合AC代码:
LL cnt=0;
int n,k;
int flag_45[20],flag_135[20];
//回溯法
void solve(int prev_s,int remain,int n){
if(remain==0){
cnt++;
return ;
}
for(int s=prev_s+1;s<=2*n-1-remain;s++){
for(int i=0;i<n;i++){
int j=s-i;
if(j>=0&&j<n&&!flag_45[i+j]&&!flag_135[n-1+j-i]){
flag_45[i+j]=flag_135[n-1+j-i]=1;
solve(s,remain-1,n);
flag_45[i+j]=flag_135[n-1+j-i]=0;
}
}
}
}
//12.33s打表结果
int ans[9][65]=
{
{},
{1,1},
{1,4,4,0},
{1,9,26,26,8,0},
{1,16,92,232,260,112,16,0},
{1,25,240,1124,2728,3368,1960,440,32,0},
{1,36,520,3896,16428,39680,53744,38368,12944,1600,64,0},
{1,49,994,10894,70792,282248,692320,1022320,867328,389312,81184,5792,128,0,},
{1,64,1736,26192,242856,1444928,5599888,14082528,22522960,22057472,12448832,3672448,489536,20224,256,0}
};
int main()
{
while(scanf("%d%d",&n,&k),n+k){
// 回溯解法 TLE 当输入8 11、12 等样例时 需要1~2秒时间计算,不过打表时就算它跑个10分钟能出结果这样能A题 打表出奇迹
// cnt=0;
// FILL(flag_45,0);
// FILL(flag_135,0);
// solve(-1,k,n);
// printf("%lld\n",cnt);
//想一想此时的酸爽
printf("%d\n",ans[n][k]);
}
//打表
// for(int n=1;n<=8;n++){
// for(int k=0;k<=n*n;k++){
// cnt=0;
// solve(-1,k,n);
// printf("%lld,",cnt);
// }
// printf("\n");
// }
return 0;
}