ural 1029. Ministry (dp)

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章