题意:给你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; }