Problem B. 小胖办证
时间限制 1000 ms
内存限制 128 MB
题目描述
xuzhenyi要办个签证。办证处是一座M层的大楼,1< =M< =100。
每层楼都有N个办公室,编号为1..N(1< =N< =500)。每个办公室有一个签证员。
签证需要让第M层的某个签证员盖章才有效。
每个签证员都要满足下面三个条件之一才会给xuzhenyi盖章:
- 这个签证员在1楼
- xuzhenyi的签证已经给这个签证员的正楼下(房间号相同)的签证员盖过章了。
- xuzhenyi的签证已经给这个签证员的相邻房间(房间号相差1,楼层相同)的签证员盖过章了。
每个签证员盖章都要收取一定费用,这个费用不超过1000000000。
找出费用最小的盖章路线,使签证生效
输入数据
第 11 行两个整数 MM 和 NN 。
接下来 MM 行每行 NN 个整数,第 ii 行第 jj 个数表示第 ii 层的第 jj 个签证员收取的费用。
输出数据
按顺序打出你经过的房间的编号,每行一个数。
如果有多条费用最小的路线,输出任意一条。
样例输入
3 4
10 10 1 10
2 2 2 10
1 10 10 10
样例输出
3
3
2
1
1
思路分析:
dp 正反各一遍,保证左右可以互相更新,路径的话,建立node数组保存子节点,到时候直接查找就可以。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<math.h>
#define INF 0x7FFFFFFF //int 最大值
#define LLINF 9223372036854775807 //long long 最大值
#define maxN 505
#define maxM 105
#define ll long long
using namespace std;
// dp 正反各一遍,保证左右可以互相更新
//然后建立node保存子节点,之后遍历即可
//保存子节点
struct node{
int x, y;
node() {}
node(int x1, int y1){
this->x=x1;
this->y=y1;
}
}b[maxM][maxN];
int n, m;
long long a[maxM][maxN], dp[maxM][maxN];
void out(int x, int y)
{
if(x == 0 || y == 0) return ;
out(b[x][y].x, b[x][y].y);
printf("%d\n", y);
}
int main()
{
for(int i=0;i<maxM;i++)//设置最大值,即使越界也会保持结果正确
for(int j=0;j<maxN;j++)
dp[i][j]=LLINF;
//memset(dp[i], LLINF, sizeof(dp[i]));//memset:会报错,数据范围太大。
//cout<<dp[0][0]<<" "<<dp[1][1]<<endl;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%d", &a[i][j]);
for(int i = 1; i <= m; i++)//初始化第一层
dp[1][i] = a[1][i];
for(int i = 2; i <= n; i++)//两次dp
{
for(int j = 1; j <= m; j++)
{
ll n1 = dp[i - 1][j];
ll n2 = dp[i][j - 1];
ll n3 = dp[i][j + 1];
if(n1 <= n2 && n1 <= n3)
{
dp[i][j] = n1 + a[i][j];
b[i][j] = node(i - 1, j);
}
else if(n2 <= n1 && n2 <= n3)
{
dp[i][j] = n2 + a[i][j];
b[i][j] = node(i, j - 1);
}
else
{
dp[i][j] = n3 + a[i][j];
b[i][j] = node(i, j + 1);
}
}
for(int j = m; j >= 1; j--)
{
ll n1 = dp[i - 1][j];
ll n2 = dp[i][j - 1];
ll n3 = dp[i][j + 1];
if(n1 <= n2 && n1 <= n3)
{
dp[i][j] = n1 + a[i][j];
b[i][j] = node(i - 1, j);
}
else if(n2 <= n1 && n2 <= n3)
{
dp[i][j] = n2 + a[i][j];
b[i][j] = node(i, j - 1);
}
else
{
dp[i][j] = n3 + a[i][j];
b[i][j] = node(i, j + 1);
}
}
}
ll minR = LLINF;
int index;
for(int i = 1; i <= m; i++)
if(dp[n][i] < minR)
{
minR = dp[n][i];
index = i;
}
out(n, index);
return 0;
}