小胖辦證

騅不逝兮發表於2020-11-15

題目描述

xuzhenyi要辦個簽證。辦證處是一座M層的大樓,1< =M< =100。
每層樓都有N個辦公室,編號為1..N(1< =N< =500)。每個辦公室有一個簽證員。
簽證需要讓第M層的某個簽證員蓋章才有效。
每個簽證員都要滿足下面三個條件之一才會給xuzhenyi蓋章:

  1. 這個簽證員在1樓
  2. xuzhenyi的簽證已經給這個簽證員的正樓下(房間號相同)的簽證員蓋過章了。
  3. 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;
}

 

相關文章