题目链接http://noi.openjudge.cn/ch0206/8786/
描述
设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):< p="">
某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。 此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。输出只需输出一个整数,表示2条路径上取得的最大的和。样例输入
8 2 3 13 2 6 6 3 5 7 4 4 14 5 2 21 5 6 4 6 3 15 7 2 14 0 0 0
样例输出
67
来源NOIP2000复赛 提高组 第四题
(WA)原来想先取一次最优解,更新后,再去一次最优解。发现过不了。这是一种贪心,这两个局部最优解不一定是整体最优解。可能两个局部最优解不可能把整个带数的格子取完,但整体最优解可以。
(AC) 后来查了一下,发现这个是一个多线程DP,同时模拟两个人走。
dp[i][j][k][r]表示第一个人走到(i,j),第二个人走到(k,r)的最优解。其可由max(dp[i-1][j][k-1][r],dp[i][j-1][k][r-1]),dp[i][j-1][k-1][r],max(dp[i-1][j][k][r-1]) + {maps[i][j](两个人位置重合时)或 maps[i][j]+maps[k][r](两个人位置不重合时)}转移而来。
WA:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<string> #include<vector> #define DEBUG(x) cout<<#x<<" = "<<x<<endl using namespace std; int N; int Matrix[15][15]; int Len[15][15]; void dfs(int i,int j,int l) { if(l==0)return ; if(Len[i+1][j]>Len[i][j+1])dfs(i+1,j,l-Matrix[i][j]); else dfs(i,j+1,l-Matrix[i][j]); if(Len[i][j]==l&&Matrix[i][j]!=0){ Matrix[i][j]=0; } } int main() { scanf("%d",&N); int ans=0; while(true){ int i,j,v; scanf("%d%d%d",&i,&j,&v); if(i==0)break; Matrix[i][j]=v; } Len[N][N]=Matrix[N][N]; for(int k=N-1;k>=1 ;k-- ){ Len[N][k]+=Len[N][k+1]; Len[k][N]+=Len[k+1][N]; } for(int i=N-1;i>=1 ;i-- ){ for(int j=N-1;j>=1 ;j-- ){ Len[i][j]=max(Len[i][j+1],Len[i+1][j])+Matrix[i][j]; } } dfs(1,1,Len[1][1]); ans=Len[1][1]; memset(Len,0,sizeof(Len)); Len[N][N]=Matrix[N][N]; for(int k=N-1;k>=1 ;k-- ){ Len[N][k]+=Len[N][k+1]; Len[k][N]+=Len[k+1][N]; } for(int i=N-1;i>=1 ;i-- ){ for(int j=N-1;j>=1 ;j-- ){ Len[i][j]=max(Len[i][j+1],Len[i+1][j])+Matrix[i][j]; } } ans+=Len[1][1]; printf("%d ",ans); }
AC:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<string> #include<vector> #define DEBUG(x) cout<<#x<<" = "<<x<<endl int N; int Matrix[15][15]; int maxLen[15][15][15][15]; using namespace std; int main() { // freopen("in.txt","r",stdin); scanf("%d",&N); while(true){ int i,j,v; scanf("%d%d%d",&i,&j,&v); if(i==0)break; Matrix[i][j]=v; } maxLen[1][1][1][1]=Matrix[1][1]; for(int i=1;i<=N ;i++ ){ for(int j=1;j<=N ;j++ ){ for(int l=1;l<=N ;l++ ){ for(int m=1;m<=N ;m++ ){ int p1=max(maxLen[i-1][j][l-1][m],maxLen[i][j-1][l][m-1]); int p2=max(maxLen[i][j-1][l-1][m],maxLen[i-1][j][l][m-1]); int r=max(p1,p2); if(i==l&&j==m)maxLen[i][j][l][m]=r+Matrix[i][j]; else { maxLen[i][j][l][m]=r+Matrix[i][j]+Matrix[l][m]; } } } } } printf("%d ",maxLen[N][N][N][N]); }
还有一个问题比较迷,为什么是从这四个状态转移过来的dp[i-1][j][k-1][r],dp[i][j-1][k][r-1]),dp[i][j-1][k-1][r],max(dp[i-1][j][k][r-1]?
参考文献
https://blog.csdn.net/heyanbai/article/details/79519532