关闭

传纸条(一)-双线性动态规划

标签: 动态规划二线程
579人阅读 评论(0) 收藏 举报
分类:

http://acm.nyist.net/JudgeOnline/problem.php?pid=61

方法一:

1 读入矩阵,注意行列。

2 采用一个四维数组记录当前两条路走到的位置(i1,j1,i2,j2)时取得的最大值,初始化为0,表示不可能到达。(0,0,0,0)1,最后减1输出。

3 一个四重循环枚举两条路分别走到的位置。由于每个点均从上或左继承而来,故内部有四个if,分别表示两个点从上上、上左、左上、左左继承来时,加上当前两个点所取得的最大值。例如,f[i][j][k][l] = max{f[i][j][k][l],f[i-1][j][k-1][l] + a[i][j] +a[k][l]},表示两点均从上面位置走来。

4 输出右下角处的最大值f[m][n][m][n],注意换行。

这题是一题很简单的二路DP。状态的记录方法五花八门,有用三维的,也有用四维的,也有人用了一些非常规的方法,但是也可以全对。

它的主要思想是:将两张纸条看作是同时从左上角传到右下角。至于题目中说的一张从左上角传到右下角,另一张反过来,这句话对解题没有任何影响。由于当步数一定时,只要知道其中一张的横坐标,那么它的纵坐标就可以用步数计算出来,所以可以仅用步数、纸条1的横坐标、纸条2的横坐标,共三维即可记录下状态。而用四维数组(x1,y1,x2,y2)不仅浪费时间和空间,同时也产生了很多废状态。两张纸条所走的步数不同时可取的最优值是不需要考虑的。

方法二:

     方法一叙述的是四维数组,可改进成三维的,即将j2省去因为有前三项就可确定j2了。

动态转移方程
f[i][k][j]=max(f[i-1][k][j-1],f[i][k-1][j-1],f[i-1][k][j],f[i][k-1][j])+a[i][k]+a[j][i+k-j];
重合时赋值为0,则不会出现重合的情况。
该方程下面的代码是利用循环实现的,据说用记忆化深搜更容易实现,我还没试过。

我的代码:

#include<cstdio>
#include<iostream>
using namespace std;

int f[61][61][61];

int max(int x1,int x2,int x3,int x4){   //求三数最大值
	if(x1>=x2&&x1>=x3&&x1>=x4)
		return x1;
	if(x2>=x3&&x2>=x4)
		return x2;
	if(x3>=x4)
		return x3;
	return x4;
}
int main(void){
	int ncase;
	cin>>ncase;
	while(ncase--){
		int m,n,i,j,k;
		int a[61][61];
		cin>>m>>n;
		for(i=1;i<=m;i++)
			for(j=1;j<=n;j++)
				cin>>a[i][j];
		for(i=1;i<=m;i++)           //设置f边界
			for(k=1;k<=n;k++){     
			f[i][k][0]=0;
		}
		for(k=1;k<=n;k++)
			for(j=1;j<=m&&j<=k-1;j++)
				f[0][k][j]=0;
		f[1][2][2]=a[1][2]+a[2][1];
		for(i=1;i<m;i++){
			for(k=2;k<=n;k++)
				for(j=i;j<=m&&j<=i+k-1;j++){
					if(j==i)
						f[i][k][j]=0;
					else
						f[i][k][j]=max(f[i-1][k][j-1],f[i][k-1][j-1],f[i-1][k][j],f[i][k-1][j])+a[i][k]+a[j][i+k-j];
				}
		}
		cout<<f[m-1][n][m]<<endl;
	}
//	system("pause");
	return 0;
} 

相同方法优秀代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int dp[110][52][52]={{{0}}};
int main()
{
	int m,n;
	while (scanf("%d%d",&m,&n)!=EOF)
	{
		memset(dp,0,sizeof(dp));
		int x1,x2,k;
		int A[500][500];
		for (x1=1;x1<=m;x1++)
			for (x2=1;x2<=n;x2++)
				scanf("%d",&A[x1][x2]);
		for (k=1;k<=m+n-2;k++)
			for (x1=1;x1<=min(m,k+1);x1++)
				for (x2=1;x2<=min(m,k+1);x2++)
				{
					if (x1!=x2)
					  dp[k][x1][x2]=max(max(dp[k-1][x1-1][x2],dp[k-1][x1][x2-1]),max(dp[k-1][x1][x2],dp[k-1][x1-1][x2-1]))+A[x1][k-x1+2]+A[x2][k-x2+2];
					else
						dp[k][x1][x2]=0;//max(max(dp[k-1][x1-1][x2],dp[k-1][x1][x2-1]),max(dp[k-1][x1][x2],dp[k-1][x1-1][x2-1]))+A[x1][k-x1+2];

				}
		/*for (k=1;k<=m+n-2;k++)
		{
			printf("k:");
			for (x1=1;x1<=min(m,k+1);x1++)
				for (x2=1;x2<=min(m,k+1);x2++)
					printf("dp[%d][%d][%d]:%d ",k,x1,x2,dp[k][x1][x2]);
			printf("\n");
		}*/

		printf("%d\n",dp[m+n-2][m-1][m]);
	}
	return 0;
}


参考:http://blog.sina.com.cn/s/blog_5d0d0f450100rjg1.html

http://blog.csdn.net/immiao/article/details/17050949

http://outofmemory.cn/wr?u=http%3A%2F%2Fwww.clanfei.com%2F2013%2F05%2F1712.html


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:31295次
    • 积分:770
    • 等级:
    • 排名:千里之外
    • 原创:44篇
    • 转载:28篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论