Mr. F. 想让部长批阅签署一份文件。但只有当部长的下属部门核准后,部长才签署一份文件。部门是一座M层的建筑物,从地面开始数起为1到M层。1<=M<=100.每一层有N个房间(1<=N<=500),也是从1到N编号。每一个房间里有且只有一个官员。 一份文件要被部门签署,必须有至少一位(第M层建筑物里的)官员签署;一个官员必须至少满足以下一项条件才能签署一个文件:
条件a:该官员在第一层工作。
条件b:该文件已经被楼下同一间房的官员签署。
条件c:该文件已经被隔壁的官员签署(所谓隔壁,是指同一层,且房间号相差为1。)
每一个官员签署一份文件,收取一点费用,这个费用为不超过10^9的正整数。 请找出签署一份文件要付出的最少费用。
首行为2个整数,空格隔开。第一个数为M,表示M层;第二数为N,表示每层N个房间。 以下M行,每行N个整数,空格隔开,描述每间房子的官员签署一份文件收取的费用(第l行的第k个整数表示第l层的第k间房的费用)。
求出让文件顺利签署所经过的房间号,这必须是付款最少的路线。 假如有多个方案,输出任一个即可。
3 4 10 10 1 10 2 2 2 10 1 10 10 10
3 3 2 1 1
可以假设总是存在让文件签署的路子,费用总数不超过10^9
分析:记忆化搜索。
Code:
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <vector> #include <queue> #include <cmath> #include <map> #include <set> #define LL long long #define pb push_back #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; const int inf=0x3f3f3f3f; const int maxn=105; int Map[maxn][maxn*5],dp[maxn][maxn*5],dir[maxn][maxn*5]; int n,m; int dfs(int x,int y){ if(y>m||y<1) return inf; if(x==1) return Map[x][y]; if(dp[x][y]<inf) return dp[x][y]; int tmp=dfs(x-1,y)+Map[x][y]; if(tmp<dp[x][y]){ dp[x][y]=tmp; dir[x][y]=-1; } tmp=dfs(x,y-1)+Map[x][y]; if(tmp<dp[x][y]){ dp[x][y]=tmp; dir[x][y]=-2; } tmp=dfs(x,y+1)+Map[x][y]; if(tmp<dp[x][y]){ dp[x][y]=tmp; dir[x][y]=2; } return dp[x][y]; } void print(int x,int y){ if(x==1) { if(n>1) printf("%d ",y); else printf("%d\n",y); return ; } if(dir[x][y]==-1) print(x-1,y); else if(dir[x][y]==-2) print(x,y-1); else if(dir[x][y]==2) print(x,y+1); if(x==n) printf("%d\n",y); else printf("%d ",y); } int main() { scanf("%d %d",&n,&m); memset(dp,inf,sizeof(dp)); memset(dir,0,sizeof(dir)); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&Map[i][j]); } } int pay=inf,id; for(int i=1;i<=m;i++){ int tmp=dfs(n,i); if(tmp<pay){ pay=tmp; id=i; } } print(n,id); return 0; }