HDU-4571 Travel in time (Floyd&&(DFS||DP))

此处有目录↑

Travel in time

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

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)


Problem Description
  Bob gets tired of playing games, leaves Alice, and travels to Changsha alone. Yuelu Mountain, Orange Island, Window of the World, the Provincial Museum etc...are scenic spots Bob wants to visit. However, his time is very limited, he can’t visit them all. 
  Assuming that there are N scenic spots in Changsha, Bob defines a satisfaction value Si to each spot. If he visits this spot, his total satisfaction value will plus Si. Bob hopes that within the limited time T, he can start at spot S, visit some spots selectively, and finally stop at spot E, so that the total satisfaction value can be as large as possible. It's obvious that visiting the spot will also cost some time, suppose that it takes C i units of time to visit spot i ( 0 <= i < N ).
  Always remember, Bob can choose to pass by a spot without visiting it (including S and E), maybe he just want to walk shorter distance for saving time. 
  Bob also has a special need which is that he will only visit the spot whose satisfaction value is  strictly larger than that of which he visited last time. For example, if he has visited a spot whose satisfaction value is 50, he would only visit spot whose satisfaction value is 51 or more then. The paths between the spots are bi-directional, of course.
 

Input
  The first line is an integer W, which is the number of testing cases, and the W sets of data are following.
  The first line of each test data contains five integers: N M T S E. N represents the number of spots, 1 < N < 100; M represents the number of paths, 0 < M < 1000; T represents the time limitation, 0 < T <= 300; S means the spot Bob starts from. E indicates the end spot. (0 <= S, E < N)
  The second line of the test data contains N integers C i ( 0 <= C i <= T ), which means the cost of time if Bob visits the spot i.
  The third line also has N integers, which means the satisfaction value Si that can be obtained by visiting the spot i ( 0 <= S i < 100 ).
  The next M lines, each line contains three integers u v L, means there is a bi-directional path between spot u and v and it takes L units of time to walk from u to v or from v to u. (0 <= u, v < N, 0 <= L <= T)
 

Output
  Output case number in the first line (formatted as the sample output).
  The second line contains an integer, which is the greatest satisfaction value.
If Bob can’t reach spot E in T units of time, you should output just a “0” (without quotation marks).
 

Sample Input
   
   
   
   
1 4 4 22 0 3 1 1 1 1 5 7 9 12 0 1 10 1 3 10 0 2 10 2 3 10
 

Sample Output
   
   
   
   
Case #1: 21


解法一:Floyd+记忆化DFS

第一反应就是Floyd处理出任意两点间最短距离,然后dfs

结果没有记忆化TLE了好久,然后又往DP想,发现可解,不过还是觉得dfs能过,找了一些dfs解法的题解,发现大神都是加上记忆化(不加记忆化的剪纸根本没用,血的教训),并且添加虚拟起点和终点以消除特殊情况。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=105;

int n,m,t,sta,des,ans,STA,DES;
int dis[MAXN][MAXN],c[MAXN],s[MAXN],dp[MAXN][305];

void dfs(int cur,int cost,int satis) {//dfs(cur,cost,satis)表示当前已经到达cur点且已参观
    if(cost>t||satis<dp[cur][cost])
        return ;
    dp[cur][cost]=satis;
    if(cost+dis[cur][DES]<=t) {
        for(int i=0;i<=n;++i) {
            if(cur==STA||s[i]>s[cur]) {
                dfs(i,cost+dis[cur][i]+c[i],satis+s[i]);
            }
        }
    }
}

int main() {
    int W,u,v,l,kase=0;
    scanf("%d",&W);
    while(kase<W) {
        memset(dis,0x3f,sizeof(dis));
        scanf("%d%d%d%d%d",&n,&m,&t,&sta,&des);
        STA=n+1;//添加一个必定参观的虚拟起点
        DES=n;//添加一个必定参观的虚拟终点
        c[STA]=c[DES]=s[STA]=0;
        s[DES]=MAXN;//虚拟终点满意度为MAXN,保证虚拟终点一定能被参观
        for(int i=0;i<n;++i)
            scanf("%d",c+i);
        for(int i=0;i<n;++i)
            scanf("%d",s+i);

        while(m-->0) {
            scanf("%d%d%d",&u,&v,&l);
            if(dis[u][v]>l)
                dis[u][v]=dis[v][u]=l;
        }
        for(int k=0;k<n;++k)
            for(int i=0;i<n;++i)
                for(int j=0;j<n;++j)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        for(int i=0;i<n;++i) {
            dis[STA][i]=dis[sta][i];
            dis[i][DES]=dis[i][des];
        }
        dis[STA][DES]=dis[sta][des];
        dis[STA][sta]=dis[des][DES]=0;
        ans=MAXN;
        memset(dp,0,sizeof(dp));
        dfs(STA,0,0);
        for(int j=0;j<=t;++j)
            ans=max(ans,dp[DES][j]);
        printf("Case #%d:\n%d\n",++kase,ans-MAXN);
    }
    return 0;
}


解法二:Floyd+DP

最后还是想用DP做一下,dp数组无脑初始化,又浪费好长时间找错

前面同解法一

dp[i][j]表示从起始点到i点并且参观了i点时,用时为j的最大满意度和

采用“我为人人”的方法进行状态转移,所以每次选取s值最小的点进行状态转移

为了降低复杂度,按照s值升序排序,最终复杂度为O(n*n*t)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=105;

struct Node {
    int i,s;
    bool operator < (const Node& a) const {
        return s<a.s;
    }
}p[MAXN];

int n,m,t,sta,des,ans,STA,DES,len;
int dis[MAXN][MAXN],c[MAXN],s[MAXN],dp[MAXN][305];

int main() {
    int W,u,v,l,kase=0,cur,nxt,cost;
    scanf("%d",&W);
    while(kase<W) {
        memset(dis,0x3f,sizeof(dis));
        scanf("%d%d%d%d%d",&n,&m,&t,&sta,&des);
        STA=n+1;//添加一个必定参观的虚拟起点
        DES=n;//添加一个必定参观的虚拟终点
        c[STA]=c[DES]=len=0;
        s[DES]=MAXN;//虚拟终点满意度为MAXN,保证虚拟终点一定能被参观
        p[len].i=STA;
        p[len++].s=s[STA]=-1;
        p[len].i=DES;
        p[len++].s=s[DES];
        for(int i=0;i<n;++i)
            scanf("%d",c+i);
        for(int i=0;i<n;++i) {
            scanf("%d",s+i);
            p[len].i=i;
            p[len++].s=s[i];
        }
        sort(p,p+len);
        while(m-->0) {
            scanf("%d%d%d",&u,&v,&l);
            if(dis[u][v]>l)
                dis[u][v]=dis[v][u]=l;
        }
        for(int k=0;k<n;++k)
            for(int i=0;i<n;++i)
                for(int j=0;j<n;++j)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        for(int i=0;i<n;++i) {
            dis[STA][i]=dis[sta][i];
            dis[i][DES]=dis[i][des];
        }
        dis[STA][DES]=dis[sta][des];
        dis[STA][sta]=dis[des][DES]=0;

        memset(dp,-1,sizeof(dp));//刚开始赋值为0,又调试好久,最后终于意识到有些状态是无效的
        dp[STA][0]=0;
        for(int i=0;i<len;++i) {
            cur=p[i].i;
            for(int j=0;j<=t;++j) {
                if(dp[cur][j]!=-1) {
                    for(int k=i+1;k<len;++k) {
                        nxt=p[k].i;
                        cost=dis[cur][nxt]+j+c[nxt];
                        if(s[nxt]>s[cur]&&cost<=t) {
                            dp[nxt][cost]=max(dp[nxt][cost],dp[cur][j]+s[nxt]);
                        }
                    }
                }
            }
        }
        ans=MAXN;
        for(int j=0;j<=t;++j)
            ans=max(ans,dp[DES][j]);
        printf("Case #%d:\n%d\n",++kase,ans-MAXN);
    }
    return 0;
}


你可能感兴趣的:(dp,HDU,DFS,记忆化)