ZOJ 2634 Collecting Stones

来源:互联网 发布:足球游戏源码 编辑:程序博客网 时间:2024/06/14 21:29

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