数塔

数塔

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 24876    Accepted Submission(s): 14989


Problem Description
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:

有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

已经告诉你了,这是个DP的题目,你能AC吗?
 

Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
 

Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
 

Sample Input
  
1 5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
 

Sample Output
  
30
 

Source
  这个题之前做过,再复习一下。。
复制一个框架和你输入的树塔a一样的数组max[100][100],max数组的第N行被赋值,对应的和a数组第N行值相等。对max数组的第N行,[N-1]进行两两比较,两者中较大的加到上一行对应的位置上,与对应的a数组相加……到最后max[0][0]就是最大的数。
my code:
#include<iostream>//2084
#include<string.h>
using namespace std;
int main()
{
	int C,i,j,a[100][100],max[100][100],N;
	cin>>C;
	while(C--)
	{
		memset(max,0,sizeof(max));
       cin>>N;
       for(i=0;i<N;i++)
	   {
		   for(j=0;j<=i;j++)
			   cin>>a[i][j];
	   }
	   for(j=0;j<N;j++)
		   max[N-1][j]=a[N-1][j];
	   for(i=N-1;i>=1;i--)
	   {
		   for(j=0;j<i;j++)
		   {
			   if(max[i][j]>max[i][j+1])
			      max[i-1][j]=a[i-1][j]+max[i][j];
		       else 
                 max[i-1][j]=a[i-1][j]+max[i][j+1];
		   }
	   }
		   cout<<max[0][0]<<endl;
	}
	return 0;
	}

做了这个我想,怎么把这个路径搜索输出来呢。我当时思路是,一个数对应下面两个数,其中下面的两个数只能选一个比较大的与上面数相加才是最大的,把下面这个比较大的数,标记为true,然后从上往下,先输出顶端的数,然后这个顶端下面两个数,标记为true的输出,然后这个为true的为顶点,找这个顶点下面两个是谁标记为true,然后输出,再以这个标记为true的为顶点……就搜索出来了。但是发现了,例如如果是

5

8 7

2 4 6的话就是我之前做过的代码最大和是18但是输出的确是 5 7 4,所以我发现判断判断一个顶点下的两个数是不是标记为true,顺序必须是先判断右边的是不是true,如果不是再判断左边的是不是true(一个顶点下的两个数,都可能被标记为true,如果两个数不相等,并且都被标记为true,那么左边标记为true的是前一个顶点对应的,右边的标记为true的是这个顶点对应的)如果一个true顶点(包括max数组第一行的唯一的一个数)对应的下面的右边没有标记为true,那么左边一定标记为true是该顶点对应的;如果该顶点右边标记为true,左边没有标记为true,那么这个右边的数是该顶点对应的。该顶点同行左边的数对应的下面两个数,左边比右边数大。(如果右边数大,那么右边会标记为true,但与实际矛盾,所以左边数较大)

欢迎讨论。。

my code:

#include<iostream>//2084
#include<string.h>
using namespace std;
int main()
{
	int C,i,j,a[100][100],max[100][100],flag[100][100],N;
	cin>>C;
	while(C--)
	{
		memset(max,0,sizeof(max));
		memset(flag,false,sizeof(flag));
       cin>>N;
       for(i=0;i<N;i++)
	   {
		   for(j=0;j<=i;j++)
			   cin>>a[i][j];
	   }
	   for(j=0;j<N;j++)
		   max[N-1][j]=a[N-1][j];
	   for(i=N-1;i>=1;i--)
	   {
		   for(j=0;j<i;j++)
		   {
			   if(max[i][j]>max[i][j+1])
			   {
				   max[i-1][j]=a[i-1][j]+max[i][j];
				   flag[i][j]=true;
			   }
		       else 
			   {
				   max[i-1][j]=a[i-1][j]+max[i][j+1];
                   flag[i][j+1]=true;
			   }
		   }
	   }
	   cout<<"最大的和是:";            //5    8 7    2 4 6
	   cout<<max[0][0]<<endl;
	   cout<<"从上到下输出路径是:"<<endl;
		 cout<<a[0][0]<<endl;
		i=0,j=0;
		while(i<N-1 &&j<N-1)
		{
			 if(flag[i+1][j+1]==true)
		   {
			cout<<a[i+1][j+1]<<endl;
			i=i+1;
			j=j+1;
		   }
		 else if(flag[i+1][j]==true)
			{
			cout<<a[i+1][j]<<endl;
			i=i+1;
			}
		}
	}
	return 0;
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值