code1169 传纸条

来自:http://www.cnblogs.com/DSChan/p/4862019.html

 

题目说找来回两条不相交路径,其实也可以等价为从(1,1)到(n,m)的两条不相交路径。

 

如果是只找一条,那又回到了最经典的 dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + a[i][j]。

现在找两条,可以先把数组开到四维。

dp[x1][y1][x2][y2] = max{

 dp[x1][y1-1][x2][y2-1],

 dp[x1-1][y1][x2-1][y2],

 dp[x1-1][y1][x2][y2-1],

 dp[x1][y1-1][x2-1][y2]

}

+ a[x1][y1] + a[x2][y2]

 

 

 

 

 

 

 

要两条路径不能相交,也就是dp[x][y][x][y]属于非法状态,判断一下不能经过此状态即可。

最简单的方法是令x2>x1,因为dp[x1][y1][x2][y2]与dp[x2][y2][x1][y1]是等价的。

 

由于m和n最大到50,开四维的数组太大,当中有很多重复和浪费。

脑补一下,两张纸条同时传的话,同一时刻它们穿过的人数是相同的,根据这点可以进行降维。

令d[i][x1][x2]表示第i步两张纸条的x坐标分别是x1和x2,则y1=i-x1+2,y2=i-x2+2。

这样就可以得出dp方程

d[i][x1][x2] = max{ d[i-1][x1][x2], d[i-1][x1-1][x2], d[i-1][x1][x2-1], d[i-1][x1-1][x2-1] } + a[x1][i-x1+2] + a[x2][i-x2+2] 

 

 

 

 

 

注意答案d[n+m-2][n][n]要特算(因为这属于"不合法状态")

 

  1. #include<iostream>  
  2. #include<cassert>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<cmath>  
  7. #include<string>  
  8. #include<iterator>  
  9. #include<cstdlib>  
  10. #include<vector>  
  11. #include<stack>  
  12. #include<map>  
  13. #include<set>  
  14. using namespace std;  
  15. #define rep(i,f,t) for(int i = (f),_end_=(t); i <= _end_; ++i)  
  16. #define rep2(i,f,t) for(int i = (f),_end_=(t); i < _end_; ++i)  
  17. #define dep(i,f,t) for(int i = (f),_end_=(t); i >= _end_; --i)  
  18. #define dep2(i,f,t) for(int i = (f),_end_=(t); i > _end_; --i)  
  19. #define clr(c, x) memset(c, x, sizeof(c) )  
  20. typedef long long int64;  
  21. const int INF = 0x5f5f5f5f;  
  22. const double eps = 1e-8;  
  23.   
  24.   
  25. //*****************************************************  
  26.   
  27. int d[100][55][55];  
  28. int a[55][55];  
  29.   
  30. inline int max(int i,int j,int k,int l)  
  31. {  
  32.     return max(max(i,j),max(k,l));  
  33. }  
  34. int main()  
  35. {  
  36.     int n,m;  
  37.     scanf("%d%d",&n,&m);  
  38.     rep(i,1,n)rep(j,1,m)scanf("%d",&a[i][j]);  
  39.   
  40.     rep(i,1,n+m-2)rep(x1,max(1,i+2-m),min(n,i+1))  
  41.     {  
  42.         int y1 = i - x1 + 2;  
  43.         rep(x2,max(x1+1,i+2-m), min(n,i+1))  
  44.         {  
  45.             int y2 = i - x2 + 2;  
  46.   
  47.             d[i][x1][x2] = max(d[i-1][x1-1][x2-1], d[i-1][x1][x2-1],  
  48.                                d[i-1][x1-1][x2],d[i-1][x1][x2])  
  49.                             + a[x1][y1] + a[x2][y2];  
  50.         }  
  51.     }  
  52.     d[n+m-2][n][n] = d[n+m-3][n-1][n];  
  53.     cout<<d[n+m-2][n][n]<<endl;   //直接输出d[n+m-3][n-1][n]即可  
  54.     return 0;  
  55. }  



 

转载于:https://www.cnblogs.com/FuTaimeng/p/5588803.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值