Codevs 1169 传纸条
来源:互联网 发布:什么软件可以套花呗 编辑:程序博客网 时间:2024/06/05 07:11
题目:
http://codevs.cn/problem/1169/
题解:一二是四维,三是三维
两条路径同时dp,dp[i][j][x][y]表示第一条路径走到(i,j),第二条路径走到(x,y); 状态转移方程:dp[i][j][x][y]=max{ dp[i-1][j][x-1][y], dp[i-1][j][x][y-1], dp[i][j-1][x-1][y], dp[i][j-1][x][y-1], }+v[i][j]+v[x][y];
思路一:
dp[i][j][i][j] - = v[i][j];
对于当dp[i][j][x][y]由一个点(ii,jj)转移而来时,此点传递了两次,状态不合法;
即dp[ii][jj][ii][jj]–>dp[i][j][x][y] 不合法;
因此将dp[i][j][i][j]特殊处理:
对于dp[i][j][i][j],v[i][j]只对答案贡献一次;
正确性证明:
显然由蓝点转移到星点是不合法状态,假设蓝点由黄点转移而来;
将蓝点的dp进行特殊处理,相当于在棕色路径中挖去了一个蓝点;
那么上方的棕色路径显然小于红色路径,故由蓝点转移的这种状态不会在max中取到;
注:
也可直接将dp[i][j][i][j]设为-inf,但要注意特判起点和终点。
代码:
#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int inf=1e9+7;const int N=55;int v[N][N],dp[N][N][N][N],n,m;int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&v[i][j]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ for(int x=1;x<=n;x++){ for(int y=1;y<=m;y++){ dp[i][j][x][y]=max(max(dp[i-1][j][x-1][y],dp[i-1][j][x][y-1]), max(dp[i][j-1][x-1][y],dp[i][j-1][x][y-1]))+v[i][j]+v[x][y]; if(i==x&&j==y) dp[i][j][x][y]-=v[x][y];//特殊处理 } } } } printf("%d",dp[n][m][n][m]); return 0;}
思路二:
将y的范围由1–m,变为j+1–m;
控制了第二个点的列,保证第二个点在第一个点右侧;
除了上图dp[i-1][j][x][y-1],y=j+1这种情况外,其余情况都合法(不会由同一个点转移来)
而y-1=j,dp[i-1][j][x][j]即j=y这种情况从未循环到过,取max保证了答案的正确性;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int x=1;x<=n;x++) for(int y=j+1;y<=m;y++) dp[i][j][x][y]=max(max(dp[i-1][j][x-1][y],dp[i-1][j][x][y-1]),max(dp[i][j-1][x-1][y],dp[i][j-1][x][y-1]))+v[i][j]+v[x][y];输出dp[n][m-1][n-1][m];
思路三:
降维
由于是网格图,走的步数和x+y有某种神秘的联系,所以可以将把步数作为第一维,第一,二个点的横坐标作为二三维
#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int inf=1e9+7;const int N=200;int v[N][N],dp[N][N][N],n,m;int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&v[i][j]); for(int i=1;i<n+m;i++) for(int x=1;x<=n;x++) for(int y=1;y<=n;y++){ if(i+2-x<=0||i+2-y<=0) continue; dp[i][x][y]=max(max(dp[i-1][x-1][y],dp[i-1][x][y-1]),max(dp[i-1][x-1][y-1],dp[i-1][x][y]))+v[x][i+2-x]+v[y][i+2-y]; if(x==y) dp[i][x][y]-=v[x][i+2-x]; } printf("%d",dp[n+m-2][n][n]); return 0;}
阅读全文
0 0
- CODEVS 1169传纸条
- CODEVS 1169 传纸条
- Codevs 1169 传纸条
- codevs 1169 传纸条(NOIP)
- CODEVS 1169 传纸条(多线程DP)
- 【codevs】p1169 传纸条
- 棋盘型动态规划-codevs-1169传纸条
- 传纸条[NOIP 2008提高组][Codevs 1169]
- Codevs 1169 == 洛谷 P1006 传纸条
- Codevs 1169 传纸条 2008年NOIP全国联赛提高组
- codevs 1169 传纸条 && 1043 方格取数(棋盘DP)
- (昨天的)codevs天梯 传纸条 暴力dp
- 【wikioi】1169传纸条
- 维基1169传纸条
- wiki 1169 传纸条
- 1169 传纸条
- 1169 传纸条
- 1169 传纸条
- MyEclipse如何编写JUnit测试类
- 整除的尾数
- 数位DP入门 + 待补上最后一题
- [C++] ACE书籍推荐
- 又学一招!二维向量vector<vector<int>>在VC下的使用技巧。
- Codevs 1169 传纸条
- ZooKeeper_1_分布式
- [C++] VS中出现未将对象引用设置到对象的实例
- HDOJ 连连看 (DFS (TLE))
- Swift中值类型和引用类型
- 奇货商城重构——webpack自动化工程
- 记一次RedHat中文乱码,中文语言包安装实践
- tensorflow学习——collections.namedtuple函数
- [C++] 继承与同名成员变量