ural 1029. Ministry (dp)

33 篇文章 0 订阅
11 篇文章 0 订阅

Mr. F. wants to get a document be signed by a minister. A minister signs a document only if it is approved by his ministry. The ministry is an M-floor building with floors numbered from 1 to M, 1<=M<=100. Each floor has N rooms (1<=N<=500) also numbered from 1 to N. In each room there is one (and only one) official. 
A document is approved by the ministry only if it is signed by at least one official from the M-th floor. An official signs a document only if at least one of the following conditions is satisfied: 
Mr. F. 想让部长批阅签署一份文件。但只有当部长的下属部门核准后,部长才签署一份文件。部门是一座M层的建筑物,从地面开始数起为1到M层。1<=M<=100.每一层有N个房间(1<=N<=500),也是从1到N编号。每一个房间里有且只有一个官员。
一份文件要被部门签署,必须有至少一位(M层建筑物里的)官员签署;一个官员必须至少满足以下一项条件才能签署一个文件:

a. the official works on the 1st floor; 
b. the document is signed by the official working in the room with the same number but situated one floor below; 
c. the document is signed by an official working in a neighbouring room (rooms are neighbouring if they are situated on the same floor and their numbers differ by one). 
条件a:该官员在第一层工作。
条件b:该文件已经被楼下同一间房的官员签署。
条件c:该文件已经被隔壁的官员签署(所谓隔壁,是指同一层,且房间号相差为1。)
Each official collects a fee for signing a document. The fee is a positive integer not exceeding 10^9.
You should find the cheapest way to approve the document. 
每一个官员签署一份文件,收取一点费用,这个费用为不超过10^9的正整数。
请找出签署一份文件要付出的最少费用。 
Input

The first line of an input contains two integers, separated by space. The first integer M represents the number of floors in the building, and the second integer N represents the number of rooms per floor. Each of the next M lines contains N integers separated with spaces that describe fees (the k-th integer at l-th line is the fee required by the official working in the k-th room at the l-th floor). 
首行为2个整数,空格隔开。第一个数为M,表示M层;第二数为N,表示每层N个房间。 以下M行,每行N个整数,空格隔开,描述每间房子的官员签署一份文件收取的费用(第l行的第k个整数表示第l层的第k间房的费用)。

OutputYou should print the numbers of rooms (one per line) in the order they should be visited to approve the document in the cheapest way. If there are more than one way leading to the cheapest cost you may print an any of them. 
求出让文件顺利签署所经过的房间号,按顺序一行一个,这必须是付款最少的路线。 假如有多个方案,输出任一个即可。
Sample Input3 410 10 1 102 2 2 101 10 10 10Sample Output33211Hint 提示

You can assume that for each official there always exists a way to get the approval of a document (from the 1st floor to this official inclusively) paying no more than 10^9.
可以假设总是存在让文件签署的路子,费用总数不超过10^9


双向DP。楼下:f[i][j]=min(f[i][j],f[i-1][j]+room[i][j]);i为层数,j为房间数,room为本房间的价格
            左隔壁:f[i][j]=min(f[i][j],f[i][j-1]+room[i][j]);
            右隔壁:f[i][j]=min(f[i][j],f[i][j+1]+room[i][j]);
每一层正反各遍历一次。比较的时候要记录路径。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const int INF=0x7fffffff-1;
const int MAXM=103;
const int MAXN=503;
int room[MAXM][MAXN];//每个房间的花费
int f[MAXM][MAXN];//到这个房间的时候的最低消费
stack<int> s;//用来路径
typedef struct
{
    int l,k;
}prior;
prior p[MAXM][MAXN];//保存来源房间的路径
int main()
{
    //freopen("in.txt","r",stdin);
    int m,n;
    memset(p,0,sizeof(p));
    scanf("%d %d",&m,&n);
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&room[i][j]);
            f[i][j]=INF;
        }
    }
    for(int i=1;i<=n;i++)//给第一层的赋初值
    {
        f[1][i]=room[1][i];
    }
    for(int i=2;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(f[i-1][j]!=INF)
            if(f[i][j]>f[i-1][j]+room[i][j])//和楼下的比较
            {
                f[i][j]=f[i-1][j]+room[i][j];
                p[i][j].l=i-1;
                p[i][j].k=j;
            }
            if(j>1&&f[i][j-1]!=INF)
            if(f[i][j]>f[i][j-1]+room[i][j])//和左边隔壁比较
            {
                f[i][j]=f[i][j-1]+room[i][j];
                p[i][j].l=i;
                p[i][j].k=j-1;
            }
        }
        for(int j=n-1;j>=1;j--)
        {
            if(f[i][j+1]!=INF)
            if(f[i][j]>f[i][j+1]+room[i][j])//和右边隔壁比较
            {
                f[i][j]=f[i][j+1]+room[i][j];
                p[i][j].l=i;
                p[i][j].k=j+1;
            }
        }
    }

    int tk=1;
    for(int i=2;i<=n;i++)//找出顶层中花费最少的房间
    {
        if(f[m][tk]>f[m][i])
        {
            tk=i;
        }
    }
    int tl=m;
    while(tl&&tk) //把路径压栈
    {
        s.push(tk);
        int t1=p[tl][tk].l;
        int t2=p[tl][tk].k;
        tl=t1;
        tk=t2;
    }
    printf("%d",s.top());
    s.pop();
    while(!s.empty()) //输出栈中的路径
    {
        printf(" %d",s.top());
        s.pop();
    }

    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值