Posted on 2012-01-29 20:40
Seed-L 阅读(2676)
评论(0) 编辑 收藏 引用
1
图1给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。(自己外加一个条件,还要找出最大路的路径,并打印出来)
2
3
4
5
注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的那个数或者右边的那个数。
6
7
Input
8
9
输入的是一行是一个整数N (1 < N <= 100),给出三角形的行数。下面的N行给出数字三角形。数字三角形上的数的范围都在0和100之间。
10
11
Output
12
13
输出最大的和。
14
15
Sample Input
16
17
18
5
19
7
20
3 8
21
8 1 0
22
2 7 4 4
23
4 5 2 6 5
24
25
26
27
Sample Output
28
29
7
30
31
3
32
33
8
34
35
2
36
37
5
38
39
30
40
41
42
43
44
45
46
/**//* -------------------------------------------------------------------------------------------
47
Test.cpp
48
说明:用动态规划法来做,不过,不知道我这一种算不算.
49
(PS:没有到任何ACM online judge上面测试过,所以有错误欢迎指出)
50
51
52
动态规划法(我的大概想法):
53
1、描述通往最大值的路径的结构(描述最优解的的结构的特征)
54
55
通过最后一层的某个结点a[i][j]就是最大值路径和的最后一个结点。那么通过
56
最大值路径的最后一个结点a[i][j]时,通过a[i-1][*](*为j-1或j)的结点的路
57
径必然也是最大值的。如果有通过另外的结点a[i-1][.]的路径和比通过a[i][*]
58
的路径和要大,即产生矛盾.
59
60
61
2、递归定义最优解的值(一个递归的解)
62
63
64
根据1的结论得
65
66
[ a[i] i = 0
67
RouteMax[i] = [
68
[ max(RouteMax[i-1]左 + a[i] , RouteMax[i-1]右 + a[i]) i >= 1
69
70
71
//暂时将储存结构看成一维数组,a[i]为当前层结点,RouteMax[i]为目前最大路径和
72
73
74
75
76
3、按自底向上的方式计算最优解的值
77
(计算出最大路径和并记录,其实我这里应该没有最到自底向上的方式,而是采用了自顶向下的备忘录
78
方式,记录每一个子问题的解.如果不用记录路径的话,应该就可以很自然而然地采用自底向上的方式,
79
从最后一个结点出发,而且不用记录路径,代码会减少很多。//后面会给出网络上别人的解法)
80
81
在计算最大路径和的时候,用表b来累加记录每一个结点,在求最大路径和的值。用表iPos来记录
82
每一层最大路径和经过的结点。其中每一个iPos[i],都由第i+1层决定,因为是不是最大,只有下
83
一层才能决定.
84
85
PS:表b定义了一种新结构,方便记录
86
87
88
4、由计算出的结果构造一个最优解(输出最大值和路径)
89
90
因为在第3步已经用表iPos记录了路径,所以直接遍历一次表iPos即可输出路径.
91
92
93
-----------------------------------------------------------------------
94
95
PS:刚刚看完《算法导论》动态规划这一章,所以想拿一道题来看看自己有没有理解到。
96
97
虽然算法思想已经有书本提供,但是实际想+写+调试也差不多用了一个上午+下午的时间
98
99
而且还不知道理解得对不对,还有做得对不对。所以如果有错误,希望前辈们指出。谢谢
100
101
102
5、算法分析:
103
算法的主要时间应该都是花费在LargestWay计算最大值以及记录路径上面,里面有一个双重迭代,外加一个for,一些常数时间的操作
104
时间复杂度应该是O(n^2)(失败。。。)
105
辅助空间比较多,主要是用在表b上面,是O(n^2)么?
106
107
--------------------------------------------------------------------------------------------- */
108
109
110
#include<stdio.h>
111
112
113
#define MAX 100
114
115
typedef struct Array //定义一个种新结构方便记录
116

{
117
int iLeft ; //最大值是从左传给当前结点的
118
int iRight ; //最大值是从右传给当前结点的
119
int iSum ; //当前结点的值
120
} Array ;
121
122
123
124
int LargestWay(int a[][MAX], Array b[][MAX] ,int *p ,int n ) ;
125
126
127
128
int main(void)
129

{
130
131
int a[MAX][MAX] ;
132
133
Array b[MAX][MAX] ;
134
135
int iPos[MAX] ; //定位每一层中最大的元素
136
137
int i = 0 ;
138
139
int j = 0 ;
140
141
int t = 0 ;
142
143
int iSum = 0 ; //最大值
144
145
int k = 0 ;
146
147
while(scanf("%d",&t) || 0 == t)
148
{
149
150
for(i = 0 ; i < t ; i++)
151
{
152
for(j = 0 ; j <= i ; j++)
153
{
154
scanf("%d",&a[i][j]) ;
155
156
b[i][j].iSum = a[i][j] ;
157
b[i][j].iLeft = b[i][j].iRight = b[i][j].iSum ;
158
159
}
160
}
161
162
163
iSum = LargestWay(a,b,iPos,t) ;
164
165
for(i = 0 ; i < t ; i++) //表的作用在于此
166
{
167
printf("%d\n",a[i][iPos[i]]);
168
}
169
170
printf("%d\n\n",iSum) ;
171
172
173
}
174
175
return 0 ;
176
}
177
178
179
int LargestWay(int a[][MAX], Array b[][MAX] ,int *p ,int n )
180

{
181
int i = 0 ;
182
int j = 0 ;
183
int iMax = a[0][0] ; // 0或者更佳
184
185
p[0] = 0 ; //第一个位置无庸置疑
186
187
188
//从第一个结点,开始将最大值往下传,Array的左右成员就是记录路径用的
189
190
for(i = 1 ; i < n ; i++)
191
{
192
for(j = 0 ,iMax = 0 ; j <= i ; j++)
193
{
194
if(0 == j ) //三角形左边界的结点
195
{
196
b[i][j].iLeft += b[i-1][j].iSum ;
197
b[i][j].iRight = 0 ;
198
199
b[i][j].iSum = ( b[i][j].iLeft > b[i][j].iRight ) ? b[i][j].iLeft : b[i][j].iRight ;
200
201
if(b[i][j].iSum >= iMax)
202
{
203
p[i-1] = j ; //修改一下数组定位,原来是p[i] = j
204
iMax = b[i][j].iSum ;
205
}
206
207
} // if
208
209
210
else if(i == j) //三角形右边界的结点
211
{
212
b[i][j].iRight += b[i-1][j-1].iSum ;
213
b[i][j].iLeft = 0 ;
214
215
b[i][j].iSum = ( b[i][j].iLeft > b[i][j].iRight ) ? b[i][j].iLeft : b[i][j].iRight ;
216
217
if(b[i][j].iSum >= iMax)
218
{
219
p[i-1] = j - 1 ;
220
iMax = b[i][j].iSum ;
221
}
222
223
}//else -if
224
225
else /**/////三角形中间的结点
226
{
227
b[i][j].iLeft += b[i-1][j].iSum ;
228
b[i][j].iRight += b[i-1][j-1].iSum ;
229
230
b[i][j].iSum = ( b[i][j].iLeft > b[i][j].iRight ) ? b[i][j].iLeft : b[i][j].iRight ;
231
232
if(b[i][j].iSum >= iMax)
233
{
234
p[i-1] = ( b[i][j].iLeft > b[i][j].iRight ) ? j : j - 1; //要么是j-1 要么是j
235
iMax = b[i][j].iSum ;
236
}
237
238
} //else -if
239
240
}//inside for
241
}//outside for
242
243
// 蹩脚特殊处理
244
p[0] = 0 ;
245
246
for(i = 0 ; i < n ; i++)
247
{
248
if(iMax == b[n-1][i].iSum) //找出最大值通过的最后一个结点。
249
{
250
p[n-1] = i ;
251
}
252
}
253
254
//末
255
return iMax ;
256
}
257
258
259
260
261
262
263
264
265
266
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
267
268
269
270
/**//* -----------------------------------
271
272
网络上别人的解法,不用记录路径,动态规划法
273
274
------------------------------- */
275
276
277
278
#include<iostream>
279
280
using namespace std ;
281
int main()
282

{
283
int i,j,n;
284
int a[105][105];
285
cin>>n;
286
for(i=1;i<=n;i++)
287
for(j=1;j<i+1;j++)
288
cin>>a[i][j];
289
290
291
cout << "answer \n" ;
292
293
for(i=n-1;i>0;i--)
294
for(j=1;j<=i;j++)
295
{
296
if(a[i+1][j]>=a[i+1][j+1])
297
a[i][j]+=a[i+1][j];
298
else
299
a[i][j]+=a[i+1][j+1];
300
}
301
302
cout<<a[1][1];
303
304
return 0;
305
}
306
307
308
309
310
311
312
313
314
315
316