hdu 2686
找两条从(1,1)到(n,n)的路径,使得权值最大,且节点不重叠
让两个进程同时进行。枚举步数,当x1==x2||y1==y2时跳过,得到状态转移方程
dp(k, x1, y1, x2, y2) = max(dp(k-1, x1-1, y1, x2-1, y2), dp(k-1, x1-1, y1, x2, y2-1), dp(k-1, x1, y1-1, x2-1, y2), dp(k-1, x1, y1-1,x2, y2-1)) + map(x1, y1) + map(x2, y2) ;
但是因为只能往右或者往下,所以坐标满足x+y=k+2(这里是下标从1开始,如果下标从0开始则是x+y=k);
这样方程可以降为3维
dp(k, x1, x2) = max(dp(k-1, x1-1, x2-1), dp(k-1, x1-1,x2), dp(k-1, x1, x2-1), dp(k-1, x1,x2)) + map(x1, k-x1) + map(x2, k-x2) ;
【也就是从以下上一步的情况选出最大的:A下B下。。A下B右。。A右B下。。A右B右】
当x1==x2||y1==y2时只加上一个目前的格子中的财富。
zzulioj
主要注意按照1-n存储的话,x+y=k-2;
按照0-n-1存储的话x+y=k;
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define maxx(a,b,c,d) max(max(a,b),max(c,d)) int n,m; int map[105][105]; int dp[205][105][105]; int main(){ int T; //freopen("2.txt","r",stdin); scanf("%d",&T); while(T--){ memset(map,0,sizeof(dp)); memset(dp,0,sizeof(dp)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&map[i][j]); } } dp[0][1][1]=map[1][1];//注意第一步 //x+y=k+2; for(int k=1; k<=n+m-2; k++){ for(int i=1; i<=k+1; i++){ for(int j=1; j<=k+1; j++){ dp[k][i][j]=maxx(dp[k-1][i-1][j],dp[k-1][i][j-1],dp[k-1][i-1][j-1],dp[k-1][i][j]); if(i==j){ dp[k][i][j]+=map[i][k+2-i]; } else{ dp[k][i][j]+=map[i][k+2-i]+map[j][k+2-j]; } } } } printf("%d\n",dp[m+n-2][n][n]); } return 0; }