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 for(int 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 查找问题
算法设计与分析 - 题型分析 - 第 4 弹(重复第 1 弹)
猜你喜欢
转载自www.cnblogs.com/JUSTDOINS/p/12084700.html
今日推荐
周排行