小胖办证 wzoi

小胖办证

题目描述:

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

时间限制:1000ms
空间限制:256MByte

思路:

  这道题本质是与数字三角形一样的,区别在于这道题需要记录路径并且要正着dp一次反着dp一次。实际上路径只要用一个二维数组记录每个点的父亲就行。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

struct node{
    int x, y;
    node() {}
    node(int x1, int y_1) : x(x1), y(y_1) {}
}b[111][511];

int n, m;
ll a[111][511], f[111][511];

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()
{
    memset(f, 0x3f3f3f3f, sizeof(f));
    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++)
        f[1][i] = a[1][i];
    for(int i = 2; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            ll n1 = f[i - 1][j];
            ll n2 = f[i][j - 1];
            ll n3 = f[i][j + 1];
            if(n1 <= n2 && n1 <= n3)
            {
                f[i][j] = n1 + a[i][j];
                b[i][j] = node(i - 1, j);
            }
            else if(n2 <= n1 && n2 <= n3)
            {
                f[i][j] = n2 + a[i][j];
                b[i][j] = node(i, j - 1);
            }
            else
            {
                f[i][j] = n3 + a[i][j];
                b[i][j] = node(i, j + 1);
            }
        }
        for(int j = m; j >= 1; j--)
        {
            ll n1 = f[i - 1][j];
            ll n2 = f[i][j - 1];
            ll n3 = f[i][j + 1];
            if(n1 <= n2 && n1 <= n3)
            {
                f[i][j] = n1 + a[i][j];
                b[i][j] = node(i - 1, j);
            }
            else if(n2 <= n1 && n2 <= n3)
            {
                f[i][j] = n2 + a[i][j];
                b[i][j] = node(i, j - 1);
            }
            else
            {
                f[i][j] = n3 + a[i][j];
                b[i][j] = node(i, j + 1);
            }
        }
    }
    ll mi = 9223372036854775807;
    int c;
    for(int i = 1; i <= m; i++)
        if(f[n][i] < mi)
        {
            mi = f[n][i];
            c = i;
        }
    out(n, c);
    return 0;
}

 

posted @ 2018-08-21 20:40  wbss  阅读(351)  评论(0编辑  收藏  举报