多线程类DP hdu2686@nyoj 61

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686

http://59.69.128.200/JudgeOnline/problem.php?pid=61

大意是找两条不交叉的路是其路上个数字之和最大,类似于传纸条。

先写传纸条

/* NYOJ61传纸条双线DP,大概思路如下:
 * 首先考虑题意是从左上角传到右下角,再从右下角传到左上角,并且不能重复路线上任何点,除起始点和终点外
 *  这样问题就可以转化为从起点双线走向终点,双线不相交。类似于单线DP,我们可以写出双线DP方程
 * 针对该为题我们唯一需要添加的就是限制条件,不能让此双线相交。
 * 状态转移方程:
 * d[k,x1,y1,x2,y2]=max{ d[k-1,x1-1,y1,x2-1,y2], d[k-1,x1-1,y1,x2,y2-1] ,
 *     d[k-1,x1,y1-1,x2-1,y2], d[k-1,x1,y1-1,x2,y2-1] }
 * 其中(x1,y1)、(x2,y2)分别为双线DP的在第K步的时候纸条所处的同学位置,并且x1!=x2 && y1!=y2 。
 *  但是这样一来会发现内存在有限制性OJ会超出,所以需要进行内存优化。我们发现x1=k-y1,x2=k-y2,所以
 * 我们可以把五维数组缩减至三维,该优化极其显著。但如果看过我上一期的解题报告的细心的同学学会滚动
 * 数组后,会发现该题同样可以试用滚动数组,因为动态规划方程显示了该题解过程只使用了第K,K-1两维数组
 * 所以我们可以进一步优化,至此内存方面优化以接近极限,有兴趣的可以试下。使用DP算法决定了时间上的优化基本无法进行。
*/

代码实现类似于下面的方法二

hdu2686

方法一:状态转化(转化数组)

View Code
 1 #include<iostream>
2 #include<cstring>
3 using namespace std;
4 #define N 100
5 #define Max(a,b) ((a)>(b)?(a):(b))
6 #define Min(a,b) ((a)<(b)?(a):(b))
7 int a[N][N];
8 int map[N][N];
9 int dp[N][N][N];
10 int main()
11 {
12 int i,j,k,h;
13 int n;
14 int max;
15 while(cin>>n)
16 {
17 for(i=1;i<=n;i++)
18 for(j=1;j<=n;j++)
19 cin>>a[i][j];
20
21 memset(map,0,sizeof(map));
22
23 //生成修改后的矩阵。
24 for(i=1,h=1;i<=n;i++,h=1)
25 for(j=1,k=i;j<=i;j++,k--)
26 map[i][h++]=a[k][j];
27
28 for(i=n,h=n;i>1;i--,h=n)
29 for(j=n,k=i;j>=i;j--,k++)
30 map[i+n-1][h--]=a[k][j];
31
32 memset(dp,0,sizeof(dp));
33
34 //初始化
35 dp[1][1][1]=map[1][1];
36 dp[2][1][2]=map[1][1]+map[2][1]+map[2][2];
37
38 //dp[i][j][k],第i行 取j k是的最大值。
39
40 max=dp[2][1][2];
41 for(i=3;i<=n;i++)
42 for(j=1;j<=i;j++)
43 for(k=j+1;k<=i;k++)
44 {
45
46 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j][k]);
47 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j-1][k-1]);
48 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j][k-1]);
49 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j-1][k]);
50
51 dp[i][j][k]+=(map[i][j]+map[i][k]);
52 max=Max(dp[i][j][k],max);
53 }
54
55 for(i=n+1;i<=2*n-1;i++)
56 for(j=i-n+1;j<=n;j++)
57 for(k=j+1;k<=n;k++)
58 {
59 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j][k]); //一个到i,另一个到k 是有 都向下走
60 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j-1][k-1]); //一个到i,另一个到k 是有 都向右走
61 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j][k-1]); //一个到i,另一个到k 是有 一个向下另一个向右走
62 dp[i][j][k]=Max(dp[i][j][k],dp[i-1][j-1][k]); //一个到i,另一个到k 是有 一个向右另一个向下走
63
64 dp[i][j][k]+=(map[i][j]+map[i][k]);
65 max=Max(dp[i][j][k],max);
66 }
67 printf("%d\n",max+a[n][n]); //加上最后一个都要走
68 }
69
70 return 0;
71 }

方法二:内存优化(传纸条的分析和状态方程)

View Code
 1 #include <iostream>
2 #include <cstring>
3 #include<time.h>
4 using namespace std;
5 int a[51][51];
6 int d[103][51][51];
7 int judagemax(int a,int b)
8 { return a> b ? a : b; }
9 int main()
10 {
11 int n,row,col;
12 while(cin>>n)
13 { row=col=n;
14 memset(a,0,sizeof(a));
15 memset(d,0,sizeof(d));
16 for(int i=1;i<=row;i++)
17 for (int j=1;j<=col;j++)
18 {cin>>a[i][j];}
19 d[2][1][1]=a[1][1];
20 for (int k=3;k<row+col;k++)
21 for(int i=1;i<=row;i++)
22 for (int j=1;j<=row;j++)
23 {
24 if(k-i<1 || k-j<1 ) break;
25 if(i==j) continue;
26 if(k-j>col || k-i>col) continue;
27 d[k][i][j] =judagemax(d[k-1][i-1][j],d[k-1][i-1][j-1]);
28 d[k][i][j] =judagemax(d[k][i][j],d[k-1][i][j-1]);
29 d[k][i][j] =judagemax(d[k][i][j],d[k-1][i][j]);
30 d[k][i][j] += a[i][k-i]+a[j][k-j];
31 }
32 int rc=row+col;
33 d[rc][row][row] =judagemax(d[rc-1][row-1][row],d[rc-1][row-1][row-1]);
34 d[rc][row][row] =judagemax(d[rc][row][row],d[rc-1][row][row-1]);
35 d[rc][row][row] =judagemax(d[rc][row][row],d[rc-1][row][row]);
36 d[rc][row][row] += a[row][col];
37 cout<<d[row+col][row][row]<<endl;
38 }
39 return 0;
40 }
posted @ 2011-08-03 19:14  我们一直在努力  阅读(318)  评论(0编辑  收藏  举报