HDU 4571 - Travel in time(Floyd+dijkstra+dp)

题目:

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

题意:

N个点M条边时限T,起点S终点E。

每个点都有其参观获得值以及花费,经过是可以选择参观或者是不参观,且下一个参观的地点价值比上一个要大。

M条无向边,每条边都有时间花费。

求出在时限内从起点到终点的所得最大值。

思路:

一次floyd,求出各点中间的最短路,为的是重新建有向图,因为参观地点的顺序是有要求的,符合要求的两个点连边。

须建源点和汇点,以解决参观或不参观的问题。

dp【i】【j】表示到i个点时间花费为j是的最大价值。在dijkstra中跑。

比赛时的想法是dp【i】【0/1】表示在i点取或者不取,但是状态太多,改了很久超时和爆内存。。。

AC.

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>

using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 150;
int N, M, T, S, E;
int cost[maxn], valu[maxn];
int dist[maxn][maxn];

struct edge {
    int to, c;
    edge(int tt, int cc) {
        to = tt; c = cc;
    }
};
vector<edge> g[maxn];

void init()
{
    memset(dist, 0x3f, sizeof(dist));
    for(int i = 0; i <= N; ++i) {
        dist[i][i] = 0;
    }
}
void floyd()
{
     for(int k = 0; k < N; ++k) {
        for(int i = 0; i < N; ++i){
            for(int j = 0; j < N; ++j) {
                dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]);
            }
        }
    }
}
typedef pair<int, int> pir;
int dp[maxn][maxn*3];

void dij()
{
    priority_queue<pir, vector<pir>, greater<pir> > que;
    memset(dp, 0, sizeof(dp));
    que.push(pir(0, N));
    dp[N][0] = 0;

    while(!que.empty()) {
        pir p = que.top(); que.pop();
        int v = p.second, cv = p.first;

        for(int i = 0; i < g[v].size(); ++i) {
            edge e = g[v][i];
            int cnt = cv + e.c + cost[e.to];
            if(cnt <= T && dp[e.to][cnt] < dp[v][cv] + valu[e.to]) {
                dp[e.to][cnt] = dp[v][cv] + valu[e.to];
                que.push(pir(cnt, e.to));
            }
        }
    }
    int ans = 0;
    for(int i = 0; i <= T; ++i) {
        ans = max(ans, dp[N+1][i]);
    }
    printf("%d\n", ans);

}
void build()
{
    for(int i = 0; i <= N+1; ++i) {
        g[i].clear();
    }
    for(int i = 0; i < N;  ++i) {
        for(int j = 0; j < N; ++j) {
            if(dist[i][j] != INF) {
                if(valu[i] < valu[j]) g[i].push_back(edge(j, dist[i][j]));
                //else g[j].push_back(edge(i, dist[i][j]));
            }
        }
    }
    for(int i = 0; i < N; ++i) {
        if(i == S) {
            g[N].push_back(edge(S, 0));
        }
        else {
            g[N].push_back(edge(i, dist[S][i]));
        }
        if(i == E) {
            g[E].push_back(edge(N+1, 0));
        }
        else {
            g[i].push_back(edge(N+1, dist[i][E]));
        }
    }
}
int main()
{
    //freopen("in", "r", stdin);
    int Cas;
    scanf("%d", &Cas);
    for(int cas = 1; cas <= Cas; ++cas) {
        scanf("%d %d %d %d %d", &N, &M, &T, &S, &E);
        for(int i = 0; i < N; ++i) {
            scanf("%d", &cost[i]);
        }
        for(int i = 0; i < N; ++i) {
            scanf("%d", &valu[i]);
        }
        init();
        for(int i = 0; i < M; ++i) {
            int u, v, c;
            scanf("%d%d%d", &u, &v, &c);
            dist[u][v] = min(dist[u][v], c);
            dist[v][u] = min(dist[v][u], c);
        }
        printf("Case #%d:\n", cas);
        floyd();
        build();
        dij();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值