2013成都站D題||hdu4784 bfs+DP+priority_queue(思路從spfa得到啟示)

life4711發表於2014-08-30

http://acm.hdu.edu.cn/showproblem.php?pid=4784

Problem Description
  Coach Pang loves his boyfriend Uncle Yang very much. Today is Uncle Yang’s birthday, Coach Pang wants to have a romantic candlelit dinner at Uncle Yang’s house and he has to arrive there in T minutes.
  There are N houses in their city numbered from 1 to N. Coach Pang lives in house 1 while Uncle Yang lives in house N. The houses are connected byM directed roads. It takes some time and usually a fee to pass one road. Coach Pang wants to reach Uncle Yang’s house before the dinner starts with as much money as possible.
  But the matter is not so simple. Coach Pang decides to do some salt trade on the way to Uncle Yang’s house. The host of each house offers a price of a bag of salt, so Coach Pang can make a profit from the price differences. Each time when Coach Pang arrives at a house (except the house 1 and the house N). He can buy one bag of salt, sell one bag of salt or do nothing. Coach Pang can carry at most B bags of salt with him, and he carries no salt when he leaves his house. The trading is so efficient that the time cost of trading can be ignored.
  However, the problem is more complicated than imagine. Coach Pang has a handheld device that can perform a journey around K parallel universes numbered from 0 to K-1. Coach Pang lives in the universe 0. When Coach Pang uses the device in universe i, he will be transported to the same place and the same time of universe (i+1) modK. The host of the house at the same place in different universe may offer a different price of salt. Luckily, the time cost and fee of the city roads are uniform among the K universes. The journey between universes costs no time but Coach Pang has to stand still watching the ads on the device for one minute every time before the device works. Remember, Coach Pang should never visit house 1 or house N in a universe other than universe 0, because the situation might become uncontrollable if he bumps into himself or his boyfriend in another universe.
  The time is running out. Coach Pang asks you to tell him whether he can arrive at Uncle Yang’s house in time, and how much money Coach Pang can have at most when the dinner starts. Coach Pang has R yuan at the start, and will end his journey immediately once he arrives at Uncle Yang’s house. He must arrive at Uncle Yang’s house in T minutes, and he can’t have negative amount of money anywhere anytime. Please help him!
 

Input
  The first line of the input is an integer C representing the number of test cases.
  For each test case, the first line will contain 6 integers N, M, B, K, R, T, as described above.
  (2 <= N <= 100, 0 <= M <= 200, 1 <= B <= 4, 2 <= K <= 5, 0 <= R <= 105, 0 <= T <= 200)
  The following K lines contain N integers each, indicating the price pij (0 <= i < K, 1 <= j <= N) for a bag of salt offered by the host of house j in the universe i. The price of house 1 and house N will be marked as -1.(1 <= pij <= 100)
  Then M lines follow, each contains 4 integers a, b, t and m, indicating that there is a road from house a to house b that costs t minutes of time and m yuan of money. (1 <= a,b <= N, a<> b, 1 <= t <=15, 0 <= m <= 100)
 

Output
  For each test case, output one line containing “Case #x: y”, where x is the case number (starting from 1) and y is the most money Coach Pang can have if he can have dinner with Uncle Yang on time.
  Print "Forever Alone" otherwise.
 

Sample Input
2 3 2 1 2 10 6 -1 1 -1 -1 5 -1 1 2 1 0 2 3 1 1 2 2 1 2 5 5 -1 -1 -1 -1 1 2 10 2 1 2 2 10
 

Sample Output
Case #1: 17 Case #2: Forever Alone

題意:

        有n個點,m條有向邊,有一個人要在T時間內從1走到n,並在途中進行交易,獲得儘量多的錢。這個人能帶B包鹽,除了1和n,每個點都有不同的鹽價,所以可以根據差價賺錢。每條邊有相應的時間和花費,到達一個點時有三個選擇:買一包鹽、賣一包鹽、什麼也不做,進行交易不需要時間。另外,還有K個平行世界(編號從0~K-1),每個是平行世界相應的鹽價不同,但是相應道路的花費相同,這個人每次可以從第i個平行世界跳轉到第(i+1)%K的平行世界(跳轉前後位置相同),這個過程需要花費1分鐘,但是他不能在1和n跳轉,也就是說在1和n時必須是在第0個平行世界。當他到n的時候立即停止旅行,最後問能獲得的最多的錢。 

思路:和spfa求最短路的思路很像

         用一個四維的陣列記錄在第i個城市,第t秒,在第k維空間中,有b包鹽時的最大價值。可以看出,每次行動時間都是增加的,接下來可以考慮用bfs的思想,把每個節點按時間去處理,先處理時間早的,再處理時間晚的,每次行動分為到下一個城市或者進行穿越,這兩個行動都可以選擇是否在當地進行交易,然後去更新新的狀態的值,然後插入佇列。由於要按時間的順序進行搜尋,所以這裡我用了優先佇列去搞,時間小的先出隊。需要注意的是,到達n點後是不能再進行擴充套件的,因此到這裡要跳過

幾個值得注意的點:1.到達n後不能進行擴充套件

                               2.在1和n點不能進行買和賣

                               3.n必須是第0宇宙內的n才是目的地

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

int N,M,B,K,R,T;
int head[205],ip;
struct note
{
    int v,t,m,next;
} edge[205];
void init()
{
    memset(head,-1,sizeof(head));
    ip=0;
}
void addedge(int u,int v,int t,int m)
{
    edge[ip].v=v;
    edge[ip].t=t;
    edge[ip].m=m;
    edge[ip].next=head[u];
    head[u]=ip++;
}
int p[205][205],dp[205][205][8][8],flag[202][205][8][8];

struct node
{
    int u,tm,b,k;
    node() {}
    node(int _u,int _tm,int _k,int _b)
    {
        u=_u;
        tm=_tm;
        k=_k;
        b=_b;
    }
    bool operator < (const node &a) const
    {
        return tm>a.tm;
    }
};
int bfs()
{
    int fla=0;
    memset(dp,0,sizeof(dp));
    memset(flag,0,sizeof(flag));
    dp[1][0][0][0]=R;
    flag[1][0][0][0]=true;
    priority_queue<node>q;
    q.push(node(1,0,0,0));
    while(!q.empty())
    {
        node point=q.top();
        q.pop();
        int u=point.u;
        int k=point.k;
        int b=point.b;
        int tm=point.tm;
      //  printf("(%d %d %d %d)\n",u,k,b,tm);
        if(u==N) continue;
        if(tm>T) break;
     //穿越
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;
            int t=edge[i].t;
            int cost=dp[u][tm][k][b]-edge[i].m;
            if(cost<0||tm+t>T)continue;
            if(v==N&&k!=0) continue;
            if(v==N) fla=1;
            if(u!=1&&u!=N)
            {
              //  printf("**\n");
                //buy
                if(b+1<=B&&(dp[v][tm+t][k][b+1]<cost-p[k][u]))
                {
                    dp[v][tm+t][k][b+1]=cost-p[k][u];
                    if(flag[v][tm+t][k][b+1]==0)
                    {
                        flag[v][tm+t][k][b+1]=1;
                        q.push(node(v,tm+t,k,b+1));
                    }
                }
                //sell
                if(b>0&&dp[v][tm+t][k][b-1]<cost+p[k][u])
                {
                    dp[v][tm+t][k][b-1]=cost+p[k][u];
                    if(flag[v][tm+t][k][b-1]==0)
                    {
                        flag[v][tm+t][k][b-1]=1;
                        q.push(node(v,tm+t,k,b-1));
                    }
                }
            }
            //no sell,no buy
            if(dp[v][tm+t][k][b]<cost)
            {
                dp[v][tm+t][k][b]=cost;
                if(flag[v][tm+t][k][b]==0)
                {
                    flag[v][tm+t][k][b]=1;
                    q.push(node(v,tm+t,k,b));
                }
            }
        }
        //不穿越
        int k1=(k+1)%K;
        int cost=dp[u][tm][k][b];
        if(u!=1&&u!=N)
        {
            if(cost<0)continue;
            if(tm+1>T)continue;
            //buy
            if(b+1<=B&&dp[u][tm+1][k1][b+1]<cost-p[k][u])
            {
                dp[u][tm+1][k1][b+1]=cost-p[k][u];
                if(flag[u][tm+1][k1][b+1]==0)
                {
                    flag[u][tm+1][k1][b+1]=1;
                    q.push(node(u,tm+1,k1,b+1));
                }
            }
            //sell
            if(b>0&&dp[u][tm+1][k1][b-1]<cost+p[k][u])
            {
                dp[u][tm+1][k1][b-1]=cost+p[k][u];
                if(flag[u][tm+1][k1][b-1]==0)
                {
                    flag[u][tm+1][k1][b-1]=1;
                    q.push(node(u,tm+1,k1,b-1));
                }
            }
        }
        //no buy,no sell
        if(dp[u][tm+1][k1][b]<cost)
        {
            dp[u][tm+1][k1][b]=cost;
            if(flag[u][tm+1][k1][b]==0)
            {
                flag[u][tm+1][k1][b]=1;
                q.push(node(u,tm+1,k1,b));
            }
        }
    }
    if(fla==0)
        return -1;
    int ans=0;
    for(int i=0; i<=T; i++)
    {
        for(int j=0; j<=B; j++)
        {
            ans=max(ans,dp[N][i][0][j]);
        }
    }
    return ans;
}
int main()
{
    int case1,tt=0;
    scanf("%d",&case1);
    while(case1--)
    {
        scanf("%d%d%d%d%d%d",&N,&M,&B,&K,&R,&T);
        for(int i=0; i<K; i++)
        {
            for(int j=1; j<=N; j++)
                scanf("%d",&p[i][j]);
        }
        init();
        for(int i=0; i<M; i++)
        {
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            addedge(a,b,c,d);
        }
        printf("Case #%d: ",++tt);
        int ans=bfs();
        if(ans==-1)
            printf("Forever Alone\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

(修改於2014.12.20)

相關文章