多阶段决策问题——DAG
本文为算法竞赛入门经典第九章第三节的笔记(刘汝佳. 算法竞赛入门经典.第2版[M]. 清华大学出版社, 2014.)
多阶段决策问题:每作一次决策就可以得到解的一部分,当所有决策做完之后,所有的解就“浮出水面”了。
多段图的最短路
单向TSP问题:
给定一个n*m的数字表格,找到一条从左到右的路径,使得上面的数字和最小。输出字典序最小的行号路径(每次可以从(i,j),走到(i,j+1),(i+1,j),(i-1,j)循环无限延伸没有边界)
思路:使用DAG上动态规划问题的基本思路。
- 读入数据
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cin >> tsp[i][j];
}
}
- 使用记忆化搜索的方法
int dp(int i,int j){
int& ans=dtsp[i][j];
if(ytsp[i][j])
return ans;
if(j >= n-1){
ans=tsp[i][j];
ytsp[i][j]=1;
return ans;
}
int mmin,next3[3];
next3[0]=(i-1+m)%m;
next3[1]=i;
next3[2]=(i+1)%m;
sort(next3,next3+3);
ans=min(tsp[i][j]+dp(next3[0],j+1),tsp[i][j]+dp(next3[1],j+1))+1;
for(int ii=0;ii<3;ii++){
if(tsp[i][j]+dp(next3[ii],j+1) < ans){
ans=tsp[i][j]+dp(next3[ii],j+1);
retsp[i][j]=next3[ii];
}
}
ytsp[i][j]=1;
return ans;
}
- 打印输出字典序最小的策略
int eend = min(dtsp[0][0],dtsp[1][0])+1;
int cur;
for(int i=0;i<m;i++){
if(dtsp[i][0] < eend){
eend=dtsp[i][0];
cur=i;
}
}
cout << cur+1 ;
for(int i=0;i<n-1;i++){
cur = retsp[cur][i];
cout << " " << cur+1;
}
完整程序:
#define LOCAL
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
//#include <stdio.h>
#include <cstdlib>
#include<time.h>
#include <ctype.h>
#include <sstream>
#include <assert.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define MAXN 92
using namespace std;
int tsp[11][101];
int m,n;
int dtsp[11][101];//记录从该点出发的深度
int ytsp[11][101];//记录该点是否被运算过
int retsp[11][101];//路径的记录
int dp(int i,int j){
int& ans=dtsp[