NOIP2000提高组 4.方格取数 C语言题解

问题描述:                      

设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):

某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

NOIP2000提高组 4.方格取数 C语言题解_第1张图片

 

输入描述:

输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

输出描述:

只需输出一个整数,表示2条路径上取得的最大的和。

样例输入:

 8

 2  3  13

 2  6   6

 3  5   7

 4  4  14

 5  2  21

 5  6   4

 6 3  15

 7 2  14

 0 0  0

样例输出:

  67

算法分析:

 

          通过分析我们不难发现,此题是一道棋盘形DP(动态规划)。而且与标准的方格取数存在不同,此题的特点就在此:需要取两次。

         

          标准的方格取数的状态方程为:

                                                               f(x,y)=max(f(x-1,y),(x,y-1))+data[x][y];

          此时边界为:

                                 f(i,j)=0;

          若取两次的方案均取最优解,会出现并未取完能取到的数的情况。所以说我们可以看成两人同时取。

          dp数组为储存到每个格子的最大值。

 

          dp[n][n][n][n]=max(dp[x1-1][y1][x2-1][y2],dp[x1-1][y1][x2][y2-1],dp[x1][y1-1][x2-1][y2],dp[x1][y1-1][x2][y2-1])+a[x1][y1]+a[x2][y2];

         如果x1=x2并且y1=y2,此时

                           dp[n][n][n][n]=max(dp[x1-1][y1][x2-1][y2],dp[x1-1][y1][x2][y2-1],dp[x1][y1-1][x2-1][y2],dp[x1][y1-1][x2][y2-1])+a[x1][y1];

         所以此时边界为:

                           x1=0或x2=0或y1=0或y2=0,返回0。

 

C语言例程:

 

#include
#define true 1
#define INF 9999999 
int a[11][11];
int dp[11][11][11][11];
int max(int x,int y)
{
	return (x>y)?x:y;
}
int f(int n)
{
	int x1,x2,y1,y2;
	dp[0][0][0][0]=0;
	for(x1=1;x1<=n;x1++)
		for(y1=1;y1<=n;y1++)
			for(x2=1;x2<=n;x2++)
				for(y2=1;y2<=n;y2++)
				{
					int tmp=-INF;
					tmp=max(tmp,dp[x1-1][y1][x2-1][y2]);
					tmp=max(tmp,dp[x1-1][y1][x2][y2-1]);
					tmp=max(tmp,dp[x1][y1-1][x2-1][y2]);
					tmp=max(tmp,dp[x1][y1-1][x2][y2-1]);
					if(x1==x2&&y1==y2)
						dp[x1][y1][x2][y2]=tmp+a[x1][y1];
					else
						dp[x1][y1][x2][y2]=tmp+a[x1][y1]+a[x2][y2];
				}
				return dp[n][n][n][n];
}
int main(void)
{
	int n;
	int x,y,v;
	while(scanf("%d",&n)!=EOF)
	{
		while(true)
		{
			scanf("%d %d %d",&x,&y,&v);
			if(!x&&!y&&!v)
                break;
			a[x][y]=v;
		}
		printf("%d",f(n));
	}
}

你可能感兴趣的:(NOIP2000,c语言,动态规划,dp,noip2000)