题意:给你8*8的矩阵,从(1,1)走到(8,8),每个点只能走一次,且只能走上下右,右上,右下这五个方向。问:是否能使权值和恰为m?
思路:dfs+剪枝,不错的剪枝搜索。
设当前走到(x,y),权值和为sum,g[x][y]表示(x,y)的权值。
1.后缀和剪枝。设第y列到第8列整个子矩阵和为sufSum,剪掉 sum+sufSum<m 的情况。
2.dp剪枝。设dp[x][y][d]表示在(x,y)从d方向出去到(8,8)的最小权值和,剪掉 sum+dp[x][y][d]-g[x][y]>m。设dp2[x][y][d]表示在(x,y)从d方向出去到(8,8)的最大权值和,剪掉sum+dp2[x][y][d]-g[x][y]<m。
3.sum剪枝。剪掉sum>m。
剪掉上面3条,基本可以AC了。
顺便附上#1 AC图,纪念下:
代码:
//#pragma comment(linker, "/STACK:134217728,134217728") /*128Mb*/
//#pragma comment(linker,"/STACK:33554432") /*32Mb*/
//#pragma comment(linker,"/STACK:16777216") /*16Mb*/
#include <algorithm>
#include <iostream>
#include <string>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
/*--in common define-----*/
#define N 1000010
#define E 100010
#define ll long long
#define INF 0xfffffff
const int PRIME =999983;
const int MOD =1000000007;
const int MULTI =1000000007;
/*--end in common define-*/
/*--in common use--------*/
#define CUBE(x) ((x)*(x)*(x))
#define SQ(x) ((x)*(x))
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
inline bool isodd(int x){return x&1;}
inline bool isodd(ll x) {return x&1;}
/*--end in common use----*/
int n,g[10][10];
int dp[10][10][6],dp2[10][10][6];
int dx[5]={-1,1,0,-1,1};
int dy[5]={0,0,1,1,1};
int sufSum[10];
bool visit[10][10],legal;
void dfs(int x,int y,int sum)
{
sum+=g[x][y];
int xx,yy,Min=INF;
if(sum>n) return ;
if(x==8 && y==8){
if(sum==n) legal=true;
return ;
}
for(int i=0;i<5;i++){
xx=dx[i]+x;
yy=dy[i]+y;
if(xx<1 || xx>8 || yy<1 || yy>8) continue;
if(visit[xx][yy]) continue;
if(sum+sufSum[y]<n) continue;
if(sum+dp[x][y][i]-g[x][y]>n) continue;
if(sum+dp2[x][y][i]-g[x][y]<n) continue;
visit[xx][yy]=true;
dfs(xx,yy,sum);
if(legal) return ;
visit[xx][yy]=false;
}
}
int predfs(int x,int y,int prex,int prey)
{
int xx,yy,Min=INF;
if(x==8 && y==8){
return g[8][8];
}
for(int i=0;i<5;i++){
xx=dx[i]+x;
yy=dy[i]+y;
if(xx<1 || xx>8 || yy<1 || yy>8) continue;
if(xx==prex && yy==prey) continue;
if(dp[x][y][i]!=-1) Min=min(Min,dp[x][y][i]);
else Min=min(Min,(dp[x][y][i]=predfs(xx,yy,x,y)+g[x][y]));
}
return Min;
}
int predfs2(int x,int y,int prex,int prey)
{
int xx,yy,Max=-INF;
if(x==8 && y==8){
return g[8][8];
}
for(int i=0;i<5;i++){
xx=dx[i]+x;
yy=dy[i]+y;
if(xx<1 || xx>8 || yy<1 || yy>8) continue;
if(xx==prex && yy==prey) continue;
if(dp2[x][y][i]!=-1) Max=max(Max,dp2[x][y][i]);
else Max=max(Max,(dp2[x][y][i]=predfs2(xx,yy,x,y)+g[x][y]));
}
return Max;
}
void pretreat()
{
CLR(sufSum,0);
CLR(visit,0);
visit[1][1]=true;
legal=false;
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++)
sufSum[j]+=g[i][j];
for(int i=7;i>=1;i--)
sufSum[i]+=sufSum[i+1];
for(int i=0;i<5;i++)
dp[8][8][i]=dp2[8][8][i]=g[8][8];
}
int main()
{
int re;
scanf("%d",&re);
while(re--){
scanf("%d",&n);
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++)
scanf("%d",&g[i][j]);
CLR(dp,-1);
CLR(dp2,-1);
predfs(1,1,0,0);
predfs2(1,1,0,0);
pretreat();
dfs(1,1,0);
if(legal) puts("Yes");
else puts("No");
}
return 0;
}