那23个路口 题解————2019.10.18
故事的起源不加赘述,那23个路口。 单刀直入,我直接说题的意思。 蚊子和疯子在做一件事,就是他们要在茫茫的大街上找一个出发点,然后从出发点开始,经过上下左右23次拐弯,到达一个他们也不知道的地方。 老城的街道排列的十分有规律,于是疯子和蚊子把老城的街道排布画在了一张地图上。地图上每一个点代表一个地方,而这个地方有一定的憧憬值,疯子希望可以带蚊子走过的二十三个路口的憧憬值总和是所有方案中最大的。 现在我们读入一个矩阵,如果此点为0,则这个点为起点,如果此点为-1,则这个点为障碍点,否则这个数代表憧憬值。注意起点和障碍点是没有憧憬值的,起点只有开始的时候可以达到,不可以再回来。而障碍点根本就不可以走过。这样一来,请你选择合适的路线,使走完23个路口后得到最大的憧憬值,有憧憬值的点可以重复进出,每次可以选择四个方向,上下左右。起点为第0个路口 输入格式: 第1行两个整数 n,m (茫茫大街的长和宽) 第2行到第m+1行,每行n个整数 Aij(第I行第j个地点的憧憬值) 输出格式 一个整数sum (可以得到的最大憧憬值) INPUT 4 4 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 OUTPUT 23 对于30%的数据,n,m<=50 对于全部数据 n,m<=300 0<n,m<300,每个点的憧憬值可以用longint表示。
DP题。因为每个点都可以重复进入,所以我们可以得到方程
F[k,I,j]:=max(f[k-1,i-1,j],f[k-1,I+1,j],f[k-1,I,j-1],f[k-1,I,j+1])+a[I,j];
因为有障碍点和出发点,所以我们要做出一定的预处理。
注意边界的判断
Code:
(代码源自cyh大佬
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<algorithm> #include<cctype> #include<cstring> #include<iostream> #define maxn 307 #define int long long using namespace std; const int inf=0x3f3f3f3f3f3f3f3f; int f[maxn][maxn][27],n,m,a[maxn][maxn],ans=-inf; int qread() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } signed main() { freopen("corner.in","r",stdin); freopen("corner.out","w",stdout); memset(f,-0x3f,sizeof(f)); m=qread(),n=qread(); for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { a[i][j]=qread(); if(!a[i][j]) f[i][j][0]=0; } } for(int i=1;i<=23;++i) { for(int x=1;x<=n;++x) { for(int y=1;y<=m;++y) { if(!a[x][y]||a[x][y]==-1) continue; if(x>1&&~a[x-1][y]) f[x][y][i]=max(f[x][y][i],f[x-1][y][i-1]+a[x][y]); if(x<n&&~a[x+1][y]) f[x][y][i]=max(f[x][y][i],f[x+1][y][i-1]+a[x][y]); if(y>1&&~a[x][y-1]) f[x][y][i]=max(f[x][y][i],f[x][y-1][i-1]+a[x][y]); if(y<m&&~a[x][y+1]) f[x][y][i]=max(f[x][y][i],f[x][y+1][i-1]+a[x][y]); } } } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) ans=max(ans,f[i][j][23]); cout<<ans<<'\n'; fclose(stdin),fclose(stdout); return 0; } /* 4 4 2 3 1 0 4 3 2 -1 8 2 -1 -1 1 3 -1 1 127 */