HDU 4571 Travel in time 最短路+01背包

题意:一些点,之间有双向边,每个点可以获得一个si值,但是也要付出相应ci的代价,你可以只经过那个点但是不获得那个si值,每次获得的si值要满足,大于最近一次获得的si值,也可以说,获得si值的顺序是严格从小到大的。

做的时候,先要考虑构造dp的模型,dp[i][j]就是时间为i最近一次是获得sj的值,此时获取的si的总值。初始化考虑是否获得初始点S的si值,求答案时,考虑是否获得E的si值,其实就是一样的,考虑是否获得每个点的si值作为初始化,考虑最后一次为是否获得每个点的si值做为最终答案,也就是两个循环的事。

坑来了。坑在ci可能为0,也就是说,如果你直接背包同一个t的状态可能有的先背有的后背,不同背的顺序得到的答案就会前后不一致。那么就对si排序,保证顺序是按照si来的,这样不管先背后备,就是按照si背的,不会有错。

还有一个坑,紫书的floyed打印错了,导致直接wa的没想法。

大概就是这些要注意的了。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 301;
int dp[333][111];
int dis[111][111];
int Ci[111],Si[111];

struct Node{
    int o;
    bool operator < (const Node&rhs)const{
        return Si[o]<Si[rhs.o];
    }
}mp[111];


int main()
{
//    freopen("data.in","r",stdin);
    int W,cas=1,ans,N,M,T,S,E,u,v,l;
    scanf("%d",&W);
    while(W--){
        scanf("%d%d%d%d%d",&N,&M,&T,&S,&E);
        for(int i=0;i<N;i++)
            scanf("%d",&Ci[i]);
        for(int i=0;i<N;i++)
            scanf("%d",&Si[i]);
        for(int i=0;i<N;i++)
            mp[i].o = i;
        sort(mp,mp+N);

        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++){
                dis[i][j]=INF;
                if(i==j) dis[i][j] = 0;
            }
        while(M--){
            scanf("%d%d%d",&u,&v,&l);
            if(dis[u][v]>l){
                dis[u][v] = l;
                dis[v][u] = l;
            }
        }

        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++)
                for(int k=0;k<N;k++)
                    if(dis[j][i]<=T && dis[i][k]<=T)
                        dis[j][k] = min(dis[j][k],dis[j][i]+dis[i][k]);

        memset(dp,-1,sizeof dp);
        for(int i=0;i<N;i++)
            if(Ci[i]+dis[S][i] <= T)
                dp[Ci[i]+dis[S][i]][i] = Si[i];

//        for(int i=0;i<=T;i++)
//            for(int j=0;j<N;j++){
//                int mj = mp[j].o;
//                for(int k=0;k<N;k++){
//                    int mk = mp[k].o;
//                    if(i - dis[mk][mj] - Ci[mj] >= 0 && dp[i - dis[mk][mj] - Ci[mj]][mk]!=-1){
//                        if(Si[mk] < Si[mj]){
//                            if(dp[i][mj]==-1 || dp[i][mj] < dp[i - dis[mk][mj] - Ci[mj]][mk] + Si[mj]){
//                                dp[i][mj] = dp[i - dis[mk][mj] - Ci[mj]][mk] + Si[mj];
//                            }
//                        }
//                    }
//                }
//            }

        for(int i=0;i<=T;i++)
            for(int j=0;j<N;j++){
                int mj = mp[j].o;
                if(dp[i][mj] == -1) continue;
                for(int k=0;k<N;k++){
                    int mk = mp[k].o;
                    if(Si[mj] < Si[mk] && i + dis[mj][mk] + Ci[mk] <= T){
                        if(dp[i + dis[mj][mk] + Ci[mk]][mk]==-1 || dp[i + dis[mj][mk] + Ci[mk]][mk] < dp[i][mj] + Si[mk]){
                            dp[i + dis[mj][mk] + Ci[mk]][mk] = dp[i][mj] + Si[mk];
                        }
                    }
                }
            }
        ans=0;
        for(int j=0;j<N;j++)
            for(int i=0;i<=T-dis[j][E];i++)
                ans = max(ans,dp[i][j]);
        printf("Case #%d:\n",cas++);
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值