题意:给定N个点,每个点有一个停留所需的时间,和停留能够获得的满意度,有M条边,每条边代表着两个点走动所需的时间,现在问在规定的T时间内从指定的一点S到E能够获得的最大的满意度是多少?要求停留的点的满意度要依次上升。
解法:这次虽然一看就是个DP,但是两个端点的处理要格外的注意,因为两个端点均可以选择路过的方式,而不是停留,因此需要虚拟出两个端点,两个端点分别表示路过起点和终点,虚拟端点与其他节点的距离也因注意连单向边,双向边就超时了。刚开始的时候打算终点不进行处理,而只是在搜索到这某个节点的时候特判一下是否为终点,对终点进行两种更新,一种是访问一种是路过,事后证明是不行的,因此路过的更新如果入队,那么下次进行更新的时候就会把它当作停留的意义来判定,会出现满意度递增的约束,而如果不主动入队,也会因为前面的更新而入队。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; int N, M, T, S, E, S2, E2; int ct[105]; int sa[105]; int mp[105][105]; int f[105][305]; const int INF = 0x3f3f3f3f; void floyd() { for (int k = 0; k < N; ++k) { for (int i = 0; i < N; ++i) { if (mp[i][k] == INF || i == k) continue; for (int j = 0; j < N; ++j) { if (mp[k][j] == INF || k == j) continue; if (mp[i][j] > mp[i][k] + mp[k][j]) { mp[i][j] = mp[i][k] + mp[k][j]; } } } } } char vis[105][305]; struct Node { int x, t; }info; int spfa() { memset(f, 0, sizeof (f)); memset(vis, 0, sizeof (vis)); f[S2][0] = 0; vis[S2][0] = 1; info.x = S2, info.t = 0; queue<Node>q; q.push(info); while (!q.empty()) { Node cur = q.front(); q.pop(); vis[cur.x][cur.t] = 0; int u = cur.x, v; for (int v = 0; v < N; ++v) { if (mp[u][v] == INF || v == u) continue; int tt = cur.t + ct[v] + mp[u][v]; if (tt <= T && (sa[u] < sa[v] || v == E2)) { if (f[v][tt] < f[u][cur.t] + sa[v]) { f[v][tt] = f[u][cur.t] + sa[v]; if (!vis[v][tt]) { vis[v][tt] = 1; info.x = v, info.t = tt; q.push(info); } } } } } int ret = 0; for (int i = 0; i <= T; ++i) { ret = max(ret, max(f[E][i], f[E2][i])); } return ret; } int main() { int W; scanf("%d", &W); for (int ca = 1; ca <= W; ++ca) { scanf("%d%d%d%d%d", &N, &M, &T, &S, &E); memset(mp, 0x3f, sizeof (mp)); for (int i = 0; i < N; ++i) { scanf("%d", &ct[i]); } for (int i = 0; i < N; ++i) { scanf("%d", &sa[i]); } S2 = N, sa[S2] = -1; E2 = N+1, sa[E2] = 0, ct[E2] = 0; int a, b, c; for (int i = 0; i < M; ++i) { scanf("%d %d %d", &a, &b, &c); mp[a][b] = mp[b][a] = min(c, mp[a][b]); } floyd(); for (int i = 0; i < N; ++i) { mp[S2][i] = mp[S][i]; mp[i][E2] = mp[i][E]; } mp[S2][S] = 0; mp[E][E2] = 0; N += 2; printf("Case #%d:\n%d\n", ca, spfa()); } return 0; }