题目描述
xuzhenyi要办个签证。办证处是一座M层的大楼,1< =M< =100。
每层楼都有N个办公室,编号为1..N(1< =N< =500)。每个办公室有一个签证员。
签证需要让第M层的某个签证员盖章才有效。
每个签证员都要满足下面三个条件之一才会给xuzhenyi盖章:
- 这个签证员在1楼
- xuzhenyi的签证已经给这个签证员的正楼下(房间号相同)的签证员盖过章了。
- xuzhenyi的签证已经给这个签证员的相邻房间(房间号相差1,楼层相同)的签证员盖过章了。
每个签证员盖章都要收取一定费用,这个费用不超过1000000000。
找出费用最小的盖章路线,使签证生效输入数据
第 1 行两个整数 M 和 N
接下来 M 行每行 N 个整数,第 i 行第 j 个数表示第 i 层的第 j 个签证员收取的费用。输出数据
按顺序打出你经过的房间的编号,每行一个数。
如果有多条费用最小的路线,输出任意一条。样例输入
3 4 10 10 1 10 2 2 2 10 1 10 10 10
样例输出
3 3 2 1 1
解析:动态规划,移动方式,同一层移动和上下层房间号相同的移动
先计算,同一房间号的上下层之间的花费,然后,在同一层向右走更新dp,再向左走更新dp。
#include<iostream> #include<math.h> using namespace std; int cost[105][505]; long dp[105][505]; struct Node{ int x; int y; }; Node path[105][505];//记录路径 int main(){ int m,n; cin>>m>>n; for(int i=1; i<=m; i++) for(int j=1; j<=n; j++) cin>>cost[i][j]; for(int i=1; i<=m; i++) for(int j=1; j<=n; j++) dp[i][j] = 1e9 + 1; for(int j=1; j<=n; j++){ dp[1][j]=cost[1][j]; //第一层 Node temp = {0,0}; path[1][j] = temp; } for(int i=2; i<=m; i++){ //从上到下 for(int j=1; j<=n; j++){ dp[i][j] = dp[i-1][j] + cost[i][j]; Node temp = {i-1, j}; path[i][j] = temp; } //从左到右 for(int j=2; j<=n; j++){ if(dp[i][j-1]+cost[i][j]<dp[i][j]){ dp[i][j]=dp[i][j-1]+cost[i][j]; Node temp = {i, j-1}; path[i][j] = temp; } } //从右到左 for(int j=n-1; j>0; j--){ if(dp[i][j+1]+cost[i][j]<dp[i][j]){ dp[i][j]=dp[i][j+1]+cost[i][j]; Node temp = {i, j+1}; path[i][j] = temp; } } } //找到花费最小的终点 Node end; end.x=m; long cost = 1e9 + 1; for(int j=1; j<=n; j++) if(dp[m][j]<cost){ cost = dp[m][j]; end.y = j; } int ans[1000]; int k=0; Node cur = end; //回溯路径 while(1){ if(cur.x==0) break; ans[k++]=cur.y; cur=path[cur.x][cur.y]; } for(int i=k-1; i>=0; i--) cout<<ans[i]<<endl; return 0; }