VIJOS P1493 传纸条

描述

小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。

在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。

还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。

格式

输入格式

输入第一行有2个用空格隔开的整数m和n,表示班里有m行n列(1<=m,n<=50)。 
接下来的m行是一个m*n的矩阵,矩阵中第i行j列的整数表示坐在第i行j列的学生的好心程度。每行的n个整数之间用空格隔开。

输出格式

输出共一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。

样例1

样例输入1[复制]

3 30 3 92 8 55 7 0

样例输出1[复制]

34

限制

各个测试点1s

提示

【限制】
30%的数据满足:1<=m,n<=10
100%的数据满足:1<=m,n<=50

坐标型DP,看了题目后感觉还是可做的。(后来发现别人的题解有用网络流做的)

   从坐标的左上角A出发,到达坐标的右下角B,找到一条路径,使路径的权最大。想了一下,嗯,可以先用a[i][j]存储数据,然后用d[i][j]记录状态,然后得到状态转移方程d[i][j]=max(d[i-1][j],d[i][j-1])+a[i][j],嗯可行,再一看,不对啊,这是要走两遍,从AB,再从BA,其实也可以看成是从AB找到两条路径,使路径之和最大,但是,注意,两条路径是不能有重复点的啊,那刚才的那种方法就不行了。。。。

   重新思考,是否可以用d[i][j][k],d[i][j][0]来表示第一条路,d[i][j][1]来表示第二条路,经过反复推敲,不可以。。。。

   这时候就已经有些癫狂状态了,所以暂时放弃,打算第二天继续搞,因为,灵感总是会在不经意间爆发,嘿嘿。

   第二天,把小桌子架好,笔记本一放,嗯,躺下开始想题,嘿。看了看昨天的草稿纸,其实昨天也是有翻一些资料。还看了自己曾经敲得P语言代码(估计那时候是抄的,根本没明白),只是看到用了一个四维数组,但就是想不明白。。四维数组(数据是50^4,不会爆掉)!!!诶,我好像突然就开窍了。

  既然一条路径一条路径的找,会举出反例。我刚才不是提过,可以看成是从AB的两条路径,那怎么就不能两条路一起找。这四维数组的意思我一下子就想明白了(感觉自己理解的是对的),d[i][j][x][y],[i][j]就是其中一条路的一个点,[x][y]就是另一条路的一个点,这样来个四层循环,主要的思路和单路还是一样的,方程就是

d[i][j][x][y]=max(d[i][j-1][x-1][y],d[i][j-1][x][y-1],d[i-1][j][x-1][y],d[i-1][j][x][y-1])+a[i][j]+a[x][y]

这里因为只能向下或向右走,所以有四个情况,

PS:我想,要是可以随便走的话,那就要考虑8个情况,因为每个点都有四种情况,还要保证单一条路不能出现回路,可以再增加数组来记录点的状态。

还有,因为两条路不能有公共点,所以要加判定条件,就是i!=x  &&  j!=y,满足前提条件的情况下就可以进行比较运算了。

第一次提交有RE了,看了看数据范围和自己开的数组,诶呀,卡数据的边界果然出了问题,下一次一定要注意注意,然后把数组改成60^4,提交AC

    嗯,思考过程,主要思路和注意事项就是这样,具体的可以见代码,其实很简短。

#include <stdio.h>
int d[60][60][60][60];
int a[60][60]; 
int max(int a,int b)
{
	if (a>b) return a;
	else  return b;
}
int main()
{
	int m,n,i,j,x,y;
	scanf("%d%d",&m,&n);
	for (i=1;i<=m;i++)
	  for (j=1;j<=n;j++)
	    scanf("%d",&a[i][j]);
	for (i=1;i<=m;i++)
	  for (j=1;j<=n;j++)
	    for (x=1;x<=m;x++)
		  for (y=1;y<=n;y++)
		    if (i!=x && j!=y)
			  d[i][j][x][y]=max(max(d[i-1][j][x-1][y],d[i-1][j][x][y-1]),
			                    max(d[i][j-1][x-1][y],d[i][j-1][x][y-1]))
								+a[i][j]+a[x][y];
	printf("%d\n",d[m][n-1][m-1][n]);
	return 0;							    
}


你可能感兴趣的:(VIJOS P1493 传纸条)