题目:
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;
}