算法设计与分析 - 题型分析 - 第 4 弹(重复第 1 弹)

  1 PTA-算法设计与分析-AC分析
  2 算法前提
  3 时间、空间复杂度:
  4 O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)<O(2n)<O(n!)
  5 0-1 最大子列和问题
  6 问题示例
  7 “最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
  8 
  9 分析 
 10 序列子列和属于求最大值问题,
 11 求最大值时:
 12 分治法 通过对序列的分割比较值,只能求出最大值
 13 蛮力法 不断地取每个序列的值,与最大的序列的和的值进行比较,只能求出最大值
 14 动态规划 用dp[]记录每个位置的最大值,同时可以通过dp[]<0输出子序列
 15 
 16 算法    求最大值    输出序列    时间复杂度
 17 分治    √    ×    O(nlog2n)
 18 蛮力    √    ×    O(n)
 19 动态规划    √    √    O(n)
 20 注:输出序列只是针对下列算法过程
 21 解法
 22 1、分治法
 23 此类属于求解组合问题
 24 三个区间:左a、右b、中间偏左+中间偏右c
 25 所求值为:max(三个区间)
 26 
 27 同上,递归过程为:
 28 求最大值()=aa[n]  n=1
 29 求最大值()=max(求最大值(aa[],左,mid),求最大值(aa[],mid,右),mid->左最大值+mid->右最大值)  n>1
 30 
 31 算法如下
 32 max(三个区间最大值a,b,c)
 33 {
 34 if(a<b) a=b;
 35 if(a>c) return a;
 36 else return c;
 37 }
 38 //递归求每一组最大值//
 39 int 求最大值(存序列的数组aa[],最左位数,最右位数)
 40 {
 41 int i,j;
 42 int 三个区间的最大值a,b,c;
 43 int 第三个区间的暂存值temp;
 44 //初始化第三个区间的值为0//
 45 。。。
 46 if(左==右)
 47 {
 48 if(aa[左]>0)
 49 return aa[左];
 50 else
 51 return 0;
 52 }
 53 int mid;
 54 a=求最大值(aa[],最左,mid);
 55 b=求最大值(aa[],mid,最右);
 56 for(i=mid;i>=最左;i++)
 57 {
 58 temp偏左+=aa[i];
 59 if(temp偏左>c偏左)
 60 c偏左=temp偏左;
 61 }
 62 for(i=mid;i<=最右;i++)
 63 {
 64 temp偏右+=aa[i];
 65 if(temp偏右>c偏右)
 66 c偏右=temp偏右;
 67 }
 68 return max(a,b,c);
 69 }
 70 int main()
 71 {
 72 输入aa[];
 73 n=aa[]大小;
 74 输出求最大值(aa[],0,n-1);
 75 }
 76 2、蛮力法
 77 蛮力法优化过程
 78 时间复杂度:O(n3)->O(n2)->O(n)
 79 
 80 三层循环过程
 81 int 求最大值(aa[],n)
 82 {
 83 int i,j,k;
 84 int thisSum,maxSum=0;
 85 for(i=0;i<n;i++)
 86 for(j=0;j<n;j++)
 87 {
 88 thisSum=0;
 89 for(k=0;k<n;k++)
 90 thisSum+=aa[k];
 91 if(thisSum>maxSum)
 92 maxSum=thisSum;
 93 }
 94 return maxSum;
 95 }
 96 二层循环过程
 97 int 求最大值(aa[],n)
 98 {
 99 int i,j;
100 int maxSum=0,thisSum;
101 for(i=0;i<n;i++)
102 {
103 thisSum=0;
104 for(j=0;j<n;j++)
105 {
106 thisSum+=aa[j];
107 if(thisSum>maxSum)
108 maxSum=thisSum;
109 }
110 }
111 return maxSum;
112 }
113 一层循环过程
114 int 求最大值(aa[],n)
115 {
116 int i;
117 int maxSum=0,thisSum=0;
118 for(i=0;i<n;i++)
119 {
120 thisSum+=aa[i];
121 if(thisSum<0)
122 thisSum=0;
123 if(thisSum>maxSum)
124 maxSum=thisSum;
125 }
126 return maxSum;
127 }
128 3、动态规划
129 状态转移方程为:
130 dp[0]=0;      边界条件
131 dp[j]=max{dp[j-1]+aaj,aaj}   1<=j<=n
132 
133 一版情况将aa[]和dp[]设置为全局变量,此处假使已经设置为全局变量。且aa[0]=0;
134 void 求最大值()
135 {
136 dp[0]=0;
137 for(j=1;j<+n;j++)
138 dp[j]=max(dp[j-1]+aa[j],aa[j]);
139 }
140 void 输出最大值()
141 {
142 int maxj=1;
143 int i,k;
144 //求出最大值dp[maxj]//
145 for(j=2;j<=n;j++)
146 if(dp[j]>dp[maxj])
147 maxj=j;
148 //求出子序列的起始位置//
149 for(i=maxj;i>=1;i++)
150 if(dp[i]<0)
151 break;
152 //输出子序列//
153 for(k=i+1;k<=maxj;k++)
154 cout<<a[k]<<" ";
155 }
156 0-2 0/1背包及背包问题
157 问题示例
158 有 n 个重量分别为w1、w2、···、wn的物品(物品编号为 1 ~ n ),它们的价值分别为 v1 、 v2 、 ··· 、 vn ,给定一个容量为 W 的背包。设计从这些物品中选取一部分物品放入该背包的方案,要求每个物品要么选中要么不选中,要求选中的物品不仅能够放入到背包中,而且具有最大的价值,并对表中的 4 个物品求出 W = 6 时的所有解和最佳解。
159 
160 物品编号    重量    价值
161 1    5    4
162 2    3    4
163 3    2    3
164 4    1    1
165 
166 分析
167 复杂度
168 
169 
170 算法    最优时间复杂度    花费时间地方    存储值    存储结果
171 蛮力法    O(2n)    求幂集    √    √
172 回溯法    最坏O(2n)    剪枝    √    √
173 贪心法    O(nlog2n)    排序    √    √
174 动态规划    O(nW)    求dp[][]    √    √
175 
176 解法
177 1、    蛮力法
178 0/1背包问题
179 前提:求解幂集 
180 //可使用递归求解,本题暂不使用,时间复杂度不变//
181 
182 /**
183  *    vector<vector<int > > ps;
184  *    vector<vector<int> > ps1;
185  *    vector<int> s;
186 */
187 vector<vector<int> >ps;
188 void 求解幂集(int n)
189 {
190 vector<vector<int> >ps1;
191 vector<vector<int> >::iterator it;
192 vector<int> s;
193 ps.push_back(s);
194 for(int i=1;i<=n;i++)
195 {
196 ps1=ps;
197 for(it=ps1.begin();it!=ps1.end();it++)
198 (*it).push_back(i);
199 for(it=ps1.begin();it!=ps1.end();it++)
200 ps.push_back(*it);
201 }
202 }
203 蛮力求解最佳方案
204 void 求解最佳方案(int w[],int v[],int W)
205 {
206 //计数,序号初始化为1//
207 int count=1;
208 //总重量、总价值//
209 int sumw,sumv;
210 //最大重量、最大价值初始为0//
211 int i,maxsumw=0,maxsumv=0;
212 vector<vector<int> >::iterator it;
213 vector<int>::iterator sit;
214 //输出格式:序号、选中物品、总重量、总价值、能否装入//
215 ··· ···
216 for(it=ps.begin();it!=ps.end;it++)
217 {
218 //输出序号//
219 ··· ···
220 sumw=sumv=0;
221 //输出前大括号//
222 ··· ···
223 for(sit=(*it).begin();sit!=(*it).end();sit++)
224 {
225 //输出序号//
226 ··· ···
227 sumw+=w[*sit-1];
228 sumv+=v[*sit-1];
229 }
230 //输出后大括号、总重量、总价值//
231 if(sumw<=W)
232 {
233 //输出能够装入//
234 ··· ···
235 if(sumv>maxsumv)
236 {
237 maxsumw=sumw;
238 maxsumv=sumv;
239 //标记序号//
240 maxi=count;
241 }
242 }
243 else 
244 //输出不能装入//
245 ··· ···
246 count++;
247 }
248 //输出最佳方案、选中物品、左大括号//
249 ··· ···
250 //输出标记位置的物品//
251 for(sit=ps[maxi].begin();sit!=ps[maxi].begin();sit++)
252 //输出选中物品//
253 ··· ···
254 //输出后大括号、最大重量、最大价值//
255 ··· ···
256 }
257 2、    回溯法
258 0/1背包问题
259 狭义上:回溯=DFS+剪枝;
260 广义上:带回退的(包括递归)都是回溯算法;
261 
262 情况1:装入背包中物品重量和恰好为W
263 
264 回溯法算法优化过程:
265 不带剪枝->+带左剪枝->+带右剪枝
266 
267 无剪枝
268 //物品数目//
269 int n;
270 //存放最优解//
271 int x[MAXN];
272 //最优解的总价值,初始化为0//
273 int maxv=0;
274 //参数按照顺序格式为:第 i 个物品、装入背包物品总重量、装入背包物品总价值、一个解向量op[]//
275 void dfs(int i,int tw,int tv,int op[])
276 {
277 if ( i > n )
278 {
279 if ( tw == W && tv > maxv )
280 {
281 maxv=tv;
282 for(int j=1;j<=n;j++)
283 x[j] = op [j];
284 }
285 }
286 else
287 {
288 op[i]=1;
289 dfs(i+1,tw+w[i],tv+v[i],op);
290 op[i]=0;
291 dfs(i+1,tw,tv,op);
292 }
293 }
294 
295 +左剪枝
296 void dfs(int i,int tw,int tv,int op[])
297 {
298 if(i>n)
299 {
300 if(tw == W&&tv>maxv)
301 {
302 maxv=tv;
303 for(j=1;j<=n;j++)
304 x[j]=op[j];
305 }
306 }
307 else 
308 {
309 if(tw+w[i]<W)
310 {
311 op[i]=1;
312 dfs(i+1,tw+w[i],tv+v[i],op);
313 }
314 op[i]=0;
315 dfs(i+1,tw,tv,op);
316 }
317 }
318 
319 +右剪枝
320 //添加参数rw:所有物品重量和//
321 void dfs(int i,int tw,int tv,int rw,int op)
322 {
323 if(i>n)
324 {
325 if(tw==W&&tv>maxv)
326 {
327 for(int j=1;j<=n;j++)
328 x[j]=op[j];
329 }
330 }
331 else
332 {
333 if(tw+w[i]<=W)
334 {
335 op[i]=1;
336 dfs(i+1,tw+w[i],tv+v[i],rw-w[i],op);
337 }
338 //能不能满足界限 W //
339 if(tw+rw-w[i]>=W)
340 {
341 op[i]=0;
342 dfs(i+1,tw,tv,rw-w[i],op);
343 }
344 }
345 }
346 
347 情况2:装入背包中物品重量和不超过W
348 +右剪枝不再有效,采用上界函数 bound 进行右剪枝
349 
350 //数组存放物品,成员顺序依次为序号、重量、价值、单位重量价值//也可按照结构数组定义,如贪心法中数组//
351 class TH
352 {
353 public:
354 int no;
355 int w;
356 int v;
357 double p;
358 }
359 
360 //上界判定函数//
361 int bound(int i,int tw,tv)
362 {
363 i++;
364 while(i<=n && tw+A[i].w<=W)
365 {
366 tw+=A[i].w;
367 tv+=A[i].v;
368 i++;
369 }
370 if(i<=n)
371 //第 i 个物品不能整个放入//
372 return tv+(W-tw)*A[i].p;
373 else 
374 return tv;
375 }
376 
377 //dfs//
378 void dfs(int i,int tw,int tv,int op[])
379 {
380 if(i>n)
381 {
382 maxv=tv;
383 for(int j=1;j<=n;j++)
384 x[j]=op[j];
385 }
386 else
387 {
388 if(tw+A[i].w<=W)
389 {
390 op[i]=1;
391 dfs(i+1,tw+A[i].w,tv+A[i].v,op);
392 }
393 //上界函数确定是否剪枝//
394 if(bound(i,tw,tv)>maxv)
395 {
396 op[i]=0;
397 dfs(i+1,tw,tv,op);
398 }
399 }
400 }
401 3、    贪心法
402 背包问题
403 背包问题此时可以分解物品
404 三种贪心策略
405 1.    价值最大物品
406 2.    重量最轻物品
407 3.    单位重量下价值最大物品
408 
409 第三种贪心策略,简单描述过程为
410 1.    排序
411 2.    背包余下重量 weight ,初始值为 W,初始价值 V
412 3.    第 i 个装入背包,直到能够装入最后的一件物品
413 
414 算法过程如下
415 double W;
416 double V;
417 //物品装入的数量:0~1//
418 double x[MAXN];
419 //存放物品的结构数组定义,结构定义顺序为重量、价值、单位重量价值、重载 < 按照单位重量价值递减排序//
420 struct NodeType
421 {
422 double w;
423 double v;
424 double p;
425 bool operator < (const NodeType &s) const
426 {
427 return p>s.p;
428 }
429 }
430 
431 void 求最大价值()
432 {
433 V=0;
434 double weight =W;
435 memset(x,0,sizeof(x));
436 int i=1;
437 while(A[i].w<weight)
438 {
439 x[i]=1;
440 weight-=A[i].w;
441 V+=A[i].v;
442 i++;
443 }
444 if(weight>0)
445 {
446 x[i]=weight/A[i].w;
447 V+=x[i]*A[i].v;
448 
449 }
450 }
451 最优装载问题
452 排序上花费时间较多
453 
454 //最优解向量//
455 int x[MAXN];
456 //最优解总重量//
457 int maxw;
458 //总重量//
459 int W;
460 
461 //求解//
462 void 最优装载()
463 {
464 memset(x,0,sizeof(x));
465 sort(w+1,w+n+1);
466 maxw=0;
467 int restw=W;
468 for(int i=1;i<=n&& w[i]<=restw;i++)
469 {
470 x[i]=1;
471 restw-=w[i];
472 maxw+=w[i];
473 }
474 }
475 4、    动态规划
476 0/1背包问题
477 第 i 个物品,背包剩余容量 r,dp[i][r]最优价值
478 
479 状态转移方程:
480 dp[i][0]=0;  边界条件dp[i][0]=0(1<=i<=n);
481 dp[0][r]=0;  边界条件dp[0][r]=0(1<=r<=W);
482 dp[i][r]=dp[i-1][r]; 当r<w[i]时物品i放不下;
483 dp[i][r]=max(dp[i-1][r],dp[i-1][r-w[i]]+v[i]); 否则在不放入和放入第 i 个物品之间选择最优解;
484 
485 决策是否装入时 x[] 存在两种状态:
486 x[i]=0;      不装入;
487 x[i]=1;此时 r = r -w[i];maxv=maxv+v[i];   装入;
488 
489 求出dp[][],然后进行回推。自底向上的求解过程。
490 
491 算法如下:
492 //最大价值//
493 int dp[MAXN][MAXW];
494 //是否选取//
495 int x[MAXN];
496 //最大价值//
497 int maxv;
498 
499 //求解//
500 void 求dp[][]()
501 {
502 int i,r;
503 for(i=0;i<=n;i++)
504 dp[i][0]=0;
505 for(r=0;r<=W;r++)
506 dp[0][r]=0;
507 for(i=1;i<=n;i++)
508 {
509 for(r=1;r<=W;r++)
510 //w[i]能否放入//
511 if(r<w[i])
512 dp[i][r]=dp[i-1][r];
513 else 
514 dp[i][r]=max(dp[i-1][r],dp[i-1][r-w[i]]+v[i]);
515 }
516 }
517 
518 //回推求解最优解//
519 void 选定物品()
520 {
521 int i=n,r=w;
522 maxv=0;
523 while(i>=0)
524 {
525 //对最后一个状态转移方程进行回推//
526 if(dp[i][r]!=dp[i-1][r])
527 {
528 x[i]=1;
529 maxv+=v[i];
530 r-=w[i];
531 }
532 else
533 x[i]=0;
534 i--;
535 }
536 }
537 完全背包问题
538 动态规划优化过程:
539 O(nW2)->O(nW)
540 
541 O(nW2)
542 第 i 个物品,重量不超过j,dp[i][j]最大总价值
543 fk[i][j]得到最大值时物品 i 挑选的件数
544 
545 同上,状态转移方程:
546 dp[i][0]=0;   背包不能装入任何物品时总价值为0;
547 dp[0][j]=0;   没有任何物品装入时总价值为0;
548 dp[i][j]=max{dp[i-1][j-k*w[i]]+k*v[i]};  当dp[i][j]<dp[i-1][j-k*w[i]]+k*v[i](k*w[i]<=j)时
549 fk[i][j]=k;   物品 i 取 k 件;
550 
551 算法过程如下:
552 
553 int fk[MAXN+1][MAXW+1];
554 int dp[MAXN+1][MAXW+1];
555 
556 //求解//
557 int 求解dp[][]()
558 {
559 int i,j,k;
560 for(i=1;i<=n;i++)
561 for(j=0;j<=w;j++)
562 for(k=0;k*w[i]<=j;k++)
563 {
564 if(dp[i][j]<dp[i-1][j-k*w[i]]+k*v[i])
565 {
566 dp[i][j]=dp[i-1][j-k*w[i]]+k*v[i];
567 fk[i][j]=k;
568 }
569 }
570 return dp[n][W];
571 }
572 
573 //回推求解最优解//
574 void 回推()
575 {
576 int j=n,j=W;
577 while(i>=1)
578 {
579 cout<<i<<" "<<fk[i][j];
580 j-=fk[i][j]*w[i];
581 i--;
582 }
583 }
584 
585 O(nW)
586 状态转移方程:
587 dp[i][j]=dp[i-1][j];   当j<w[i]时物品放不下;
588 dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i];
589 
590 //求解//
591 int 求解dp[][]()
592 {
593 int i,j;
594 for(i=1;i<=n;i++)
595 for(j=0;j<=W;j++)
596 {
597 if(j<w[i])
598 dp[i][j]=dp[i-1][j];
599 else
600 dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
601 }
602 return dp[n][W];
603 }
604 此时回推同0/1背包。
605 
606 0-3 求解任务分配问题
607 问题示例
608 有n(n>=1)个任务需要分配给n个人执行,每个任务只能分配给一个人,每个人只能执行一个任务,第 i 个人执行第 j 个任务的成本时c[i][j](1<=i,j<=n)。求出总成本最小的一种分配方案。
609 分析
610 复杂度
611 
612 
613 算法    时间复杂度    方案输出    最优值输出
614 蛮力法    任务分配    O(n×n!)    √    √
615 回溯法    任务分配    O(nn)    √    √
616     活动安排    O(n!)    √    √
617 动态规划    资源分配    O(m×n2)    √    √
618     会议安排    O(nlog2n)        
619 
620 解法
621 1、    蛮力法
622 任务分配问题
623 前提:求解全排列
624 //可使用递归求解,本题暂不使用,时间复杂度不变//
625 
626 //存放成本//
627 int c[MAXN][MAXN];
628 //存放全排列//
629 vector<vector<int> > ps;
630 
631 //插入 i 使得集合增加//
632 void insert(vector<int> s,int i,vector<vector<int> > &ps1)
633 {
634 vector<int> s1;
635 vector<int>::iterator it;
636 forint j=0;j<i;j++)
637 {
638 s1=s;
639 it=s1.begin()+j;
640 s1.insert(it,i);
641 ps1.push_back(s1);
642 }
643 }
644 
645 //求解全排列//
646 void 求解全排列()
647 {
648 vector<vector<int > > ps1;
649 vector<vector<int > >::iterator it;
650 vector<int> s,s1;
651 s.push_back(1);
652 ps.push_back(s);
653 for(int i=2;i<=n;i++)
654 {
655 ps1.clear();
656 for(it=ps.begin();it!=ps.end();it++)
657 //逐项插入元素//
658 insert(*it,i,ps1);
659 ps=ps1;
660 }
661 }
662 
663 蛮力法求解最优方案
664 //蛮力法求解最佳方案//
665 void 求最佳方案(int n,int &mini,int &minc)
666 {
667 求解全排列();
668 for(int i=0;i<ps.size();i++)
669 {
670 int cost=0;
671 for(int j=0;j<ps[i].size();j++)
672 cost+=c[i][ps[i][j]-1];
673 if(cost<minc)
674 {
675 minc=cost;
676 mini=i;
677 }
678 }
679 }
680 
681 2、    回溯法
682 任务分配问题
683 //临时解//
684 int x[MAXN];
685 //临时解的成本,初始化为0//
686 int cost=0;
687 //存放最优解//
688 int bestx[MAXN];
689 //最优解的成本,初始化为INF,INF为#define INF 99999//
690 int mincost = INF;
691 //表明任务 j 是否已经分配人员//
692 bool worker[MAXN];
693 
694 //为第 i 个人分配任务//
695 void dfs(int i)
696 {
697 if(i>n)
698 {
699 if(cost<mincost)
700 {
701 mincost=cost;
702 for(int j=1;j<=n;j++)
703 bestx[j]=x[j];
704 }
705 }
706 else
707 {
708 //为人员 i 进行试分配任务 j //
709 for(int j=1;j<=n;j++)
710 if(!worker[j])
711 {
712 worker[j]=true;
713 x[i]=j;
714 cost+=c[i][j];
715 dfs(i+1);
716 worker[j]=false;
717 x[i]=0;
718 cost-=c[i][j];
719 }
720 
721 }
722 }
723 活动安排问题
724 有着开始时间 bi 和结束时间 ei 
725 struct Action{
726 {
727 int b;
728 int e;
729 };
730 
731 int n;
732 //临时解向量//
733 int x[MAX];
734 //最优解向量//
735 int bestx[MAX];
736 //活动最大结束时间,初始化为0//
737 int laste=0;
738 //所有兼容活动个数,初始化为0//
739 int sum=0;
740 //最有调度方案中所兼容活动的个数,初始化为0//
741 int maxsum=0;
742 
743 //交换数值 x 和 y //
744 void swap(int &x,int &y)
745 {
746 int tem=x;
747 x=y;
748 y=tmp;
749 }
750 
751 //搜索最优解//
752 void  dfs(int i)
753 {
754 if(i>n)
755 {
756 if(sum>maxsum)
757 {
758 maxsum=sum;
759 for(k=1;k<=n;k++)
760 bestx[k]=x[k];
761 }
762 }
763 else
764 {
765 for(int j=i;j<=n;j++)
766 {
767 swap(x[i],x[j]);
768 
769 int sum1=sum;
770 int laste1=laste;
771 
772 if(A[x[j]].b>laste)
773 {
774 sum++;
775 laste=A[x[j]].e;
776 }
777 dfs(i+1);
778 swap(x[i],x[j]);
779 
780 sum=sum1;
781 laste=laste1;
782 }
783 }
784 }
785 3、    贪心法
786 活动安排问题
787 //同回溯法,定义结构类似//
788 struct Action
789 {
790 int b;
791 int e;
792 bool operator<(const Action &s) const
793 {
794 //递增排序//
795 return e<=s.e;
796 }
797 }
798 
799 Action A[];
800 bool flag[MAX];
801 int Count=0;
802 
803 //求解最大兼容性子集//
804 void 求解子集()
805 {
806 memset(flag,0,sizeof(flag));
807 sort(A+1,A+n+1);
808 //前一个兼容活动的结束时间//
809 int preend=0;
810 for(int i=1;i<=n;i++)
811 {
812 if(A[i].b>=preend)
813 {
814 flag[i]=true;
815 preend=A[i].e;
816 }
817 }
818 }
819 
820 3、动态规划
821 资源分配问题
822 n 个物品,分配至 m ,dp[i][s]为 i~m 并分配 s 个物品的获利,dnum[i][s]为dp[i][s]时对应 i 获得的物品
823 
824 状态转移方程:
825 dp[m+!][j]=0;    边界条件
826 dp[i][s]=max(v[i][j]+dp[i+1][s-j];  pnum[i][s]=dp[i][s]取最大值的j(0<=j<=n);
827 
828 由pnum反推 i 物品数
829 
830 算法过程如下:
831 //获利情况//
832 int v[MAXM][MAXM];
833 //dp//
834 int dp[MAXM][MAXM];
835 //分配人数//
836 int pnum[MAXM][MAXM];
837 int m,n;
838 
839 //求最优方案dp[][]//
840 void 求最优()
841 {
842 //参数为m获利最优、分配人数//
843 int maxf,maxj;
844 for(int j=0;j<=n;j++)
845 dp[m+1][j]=0;
846 for(int i=m;i>=1;i--)
847 for(int s=1;s<=n;s++)
848 {
849 maxf=0;
850 maxj=0;
851 for(j=0;j<=s;j++)
852 {
853 if((v[i][j]+dp[i+1][s-j])>maxf)
854 {
855 maxf=v[i][j]+dp[i+1][s-j];
856 maxj=j;
857 }
858 }
859 dp[i][s]=maxf;
860 pnum[i][s]=maxj;
861 }
862 }
863 会议安排问题
864 dp[i]订单中兼容订单的最长时间
865 状态转移方程:
866 dp[0]=订单0的时间;
867 dp[i]=max{dp[i-1],dp[j]+A[i].length};  订单 j 是结束时间早于订单 i 开始时间的最晚的订单
868 
869 pre[i]是dp[i]的前驱订单
870 1.    pre[i]=-1;  A[i]没有前驱;
871 2.    pre[i]=-2;  A[i]不被选择;
872 3.    pre[i]=j;   A[i]前面最晚的订单A[j];
873 
874 struct NodeType
875 {
876 int b;
877 int e;
878 int length;
879 bool operator<(const NodeType t) const
880 {
881 //递增排序//
882 return e<t.e;
883 }
884 };
885 
886 int n;
887 NodeType A[MAX];
888 int dp[MAX];
889 int pre[MAX];
890 
891 void 求dp[]和pre[]()
892 {
893 memset(dp,0,sizeof(dp);
894 stable_sort(A,A+n);
895 dp[0]=A[0].length;
896 
897 pre[0]=-1;
898 
899 for(int i=1;i<=n;i++)
900 {    
901 int low=0,high=i-1;
902 //二分法查找确定最晚订单A[low-1]//
903 while(low<=high)
904 {    
905 int mid=(low+high)/2;
906 if(A[mid].e<=A[i].b)
907 low=mid+1;
908 else 
909 high=mid-1;
910 }
911 //最小订单//
912 if(low==0)
913 {
914 if(dp[i-1]>=A[i].length)
915 {
916 dp[i]=dp[i-1];
917 pre[i]=-2;
918 }
919 else
920 {
921 dp[i]=A[i].length;
922 pre[i]=-1;
923 }
924 }
925 else
926 //状态转移方程,max//
927 {
928 if(dp[i-1]>=dp[low-1]+A[i].length)
929 {
930 dp[i]=dp[i-1];
931 pre[i]=-2;
932 }
933 else
934 {
935 dp[i]=dp[low-1]+A[i].length;
936 pre[i]=low-1;
937 }
938 }
939 }
940 }
941 
942 0-4 查找问题

猜你喜欢

转载自www.cnblogs.com/JUSTDOINS/p/12084700.html