多阶段决策问题(UVa 116)

在回溯法中,每个决策对应于给一个节点产生新的子树,而解的生成过程对应一颗解答树,节点的层数就是下一个待填充位置$cur$。

在多阶段决策的最优化问题,大多可以用dp解决,状态转移则类似于回溯法中的解答树。

UVa 116

$d(i,j)$表示从第此处出发到达最后一列的最小和,要求字典序最小,就同时要记录行号的最小值。

代码:

 1 //
 2 //  main.cpp
 3 //  UVa 116
 4 //
 5 //  Created by Yanbin GONG on 12/3/2018.
 6 //  Copyright © 2018 Yanbin GONG. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <stdio.h>
11 #include <string>
12 #include <string.h>
13 #include <algorithm>
14 #include <cmath>
15 
16 using namespace std;
17 
18 int m,n;
19 int cell[15][105];
20 int d[15][105];
21 int path[15][105]; //记录从该处应该走到的下一个点
22 int tmp;
23 int ans;
24 int startNode;
25 //int updown[3] = {-1,0,1}; 写在dp中,方便改变状态,满足在上下边时候的移动
26 
27 
28 int main(){
29     while(cin>>n>>m){
30         memset(d,0x3f,sizeof(d));
31         ans = 0x3f3f3f3f;
32         for(int i=1;i<=n;i++){
33             for(int j=1;j<=m;j++){
34                 cin>>cell[i][j];
35             }
36             d[i][m] = cell[i][m];//初始化边界
37         }
38         //dp
39         for(int j=m;j>1;j--){
40             
41             for(int i=1;i<=n;i++){
42                 int updown[3] = {i-1,i,i+1}; //表示接下来处在的行
43                 if(i==1) updown[0] = n;
44                 if(i==n) updown[2] = 1;
45                 //排序找到最小字典序的核心代码!因为这个WA了
46                 sort(updown,updown+3); //排序找到最小字典序的核心代码!因为这个WA了
47                 //排序找到最小字典序的核心代码!因为这个WA了
48                 for(int k=0;k<3;k++){
49                     tmp = d[i][j] + cell[updown[k]][j-1]; //到[][j-1]的总成本
50                     if(tmp<d[updown[k]][j-1]){
51                         d[updown[k]][j-1] = tmp;
52                         path[updown[k]][j-1] = i;//反向记录从[][j-1]走到[i][j]
53                     }
54                 }
55             }
56         }
57         //找到最优解的开始
58         for(int i=1;i<=n;i++){
59             if(ans>d[i][1]){
60                 ans = d[i][1];
61                 startNode = i;
62             }
63         }
64         //print
65         printf("%d",startNode);
66         int nextNode = path[startNode][1];
67         for(int j=1;j<=m;j++){
68             printf(" %d",nextNode);
69             nextNode = path[nextNode][j];
70         }
71         printf("\n%d\n",ans);
72     }
73     return 0;
74 }
View Code

这题要注意将$updown$更新后重新排序一遍,这样才能确定找到的字典序是最小的

 

posted @ 2018-03-12 22:39  摇啊摇啊  阅读(170)  评论(0编辑  收藏  举报