题目大意
有一个地图,地图上面有n个点,m条有向的路,然后经过一条路要花费一定的时间,同时还得花一定的过路费。有一个人,最初在1点,他出门的时候会带上一些钱。每经过一个点,就可以买一包盐或者卖一包盐,赚取差价,或者什么也不干。他出门带了R的钱,没有带盐。他最多能带B的钱。现在要求他在T时间内到达N点。同时又有K个平行世界,起初这个人在第0个平行世界,这个人可以在平行世界之间穿越。比如他在第i个平行世界,他可以花费1分钟穿越到第(i+1)%K个平行世界,但是在1点和N点不能穿越。现在问的就是这个人及时到达N点且在第0个平行世界的时候,能得到的最多的钱。
解题思路
参考博客:http://blog.youkuaiyun.com/qian99/article/details/16371385
(这道题真的还不是我想出来的,看了题解才有的结果)
首先,其实点不多,平行世界不多,边不多,同时B也不大,就容易想到最短路,现在有两种想法,spfa或者广搜。
听说spfa姿势不好容易被卡常数,而且HDU更加容易被卡,那么就用广搜+优先级队列吧……首先,我们要保证时间最短,因为我们的第一个保证是能够及时到达N点,然后在此基础上保证钱最多。但是这道题还要复杂些,因为有K个平行世界。那么在一个点上,就能衍生出两个大状态:往前走或者穿越。然后往前走和穿越又各有三个小状态:买一包盐,卖一包盐或者什么都不干。能扩展出来的状态有这么多,每一个状态的限制条件题里面已经给出了,剩下的事情就交给程序了……
CODE
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 100+10;
const int maxm = 200+10;
struct edge{
int v, tm, cost, next;
};
edge e[maxn<<1];
int head[maxn], tot = 0;
int n, m, K, B, R, T;
int d[maxn][maxm][6][6];
bool inq[maxn][maxm][6][6];
int prices[6][maxn];
void addedge(int u, int v, int tm, int cost){
e[tot].v = v; e[tot].tm = tm; e[tot].cost = cost;
e[tot].next = head[u]; head[u] = tot++;
}
struct Node{
int u, times, k, b;
Node(){}
Node(int a, int x, int c, int d) : u(a), times(x), k(c), b(d){}
bool operator < (const Node &rhs)const{
return times > rhs.times;
}
};
int bfs(){
memset(d, 0xff, sizeof(d));
memset(inq, 0, sizeof(inq));
d[1][0][0][0] = R;
Node node, tmp;
priority_queue<Node> que;
node = Node(1, 0, 0, 0);
inq[1][0][0][0] = 1; que.push(node);
bool flag = 0;
while(!que.empty()){
node = que.top(); que.pop();
if (node.times > T) break;
int u = node.u;
if (u == n) continue;
for (int i = head[u]; i != -1; i = e[i].next){
int v = e[i].v;
int cost, tim;
cost = d[u][node.times][node.k][node.b]-e[i].cost;
tim = node.times+e[i].tm;
if (tim > T || cost < 0) continue;
if (v == n && node.k != 0) continue;
if (v == n) flag = 1;
tmp.u = v; tmp.times = tim; tmp.k = node.k;
if (u != 1 && u != n){
if (node.b+1 <= B && cost-prices[node.k][u] > d[v][tim][node.k][node.b+1]){
d[v][tim][node.k][node.b+1] = cost-prices[node.k][u];
tmp.b = node.b+1;
if (!inq[tmp.u][tmp.times][tmp.k][tmp.b]){
inq[tmp.u][tmp.times][tmp.k][tmp.b] = 1;
que.push(tmp);
}
}
if (node.b > 0 && cost+prices[node.k][u] > d[v][tim][node.k][node.b-1]){
d[v][tim][node.k][node.b-1] = cost+prices[node.k][u];
tmp.b = node.b-1;
if (!inq[tmp.u][tmp.times][tmp.k][tmp.b]){
inq[tmp.u][tmp.times][tmp.k][tmp.b] = 1;
que.push(tmp);
}
}
}
if (cost > d[v][tim][node.k][node.b]){
d[v][tim][node.k][node.b] = cost;
tmp.b = node.b;
if (!inq[tmp.u][tmp.times][tmp.k][tmp.b]){
inq[tmp.u][tmp.times][tmp.k][tmp.b] = 1;
que.push(tmp);
}
}
}
if (u != 1 && u != n){
int cost = d[u][node.times][node.k][node.b];
tmp.u = u; tmp.k = (node.k+1)%K;
tmp.times = node.times+1;
if (tmp.times>T) continue;
if (node.b+1 <= B && cost-prices[node.k][u] > d[u][tmp.times][tmp.k][node.b+1]){
d[u][tmp.times][tmp.k][node.b+1] = cost-prices[node.k][u];
tmp.b = node.b+1;
if (!inq[tmp.u][tmp.times][tmp.k][tmp.b]){
inq[tmp.u][tmp.times][tmp.k][tmp.b] = 1;
que.push(tmp);
}
}
if (node.b > 0 && cost+prices[node.k][u] > d[u][tmp.times][tmp.k][node.b-1]){
d[u][tmp.times][tmp.k][node.b-1] = cost+prices[node.k][u];
tmp.b = node.b-1;
if (!inq[tmp.u][tmp.times][tmp.k][tmp.b]){
inq[tmp.u][tmp.times][tmp.k][tmp.b] = 1;
que.push(tmp);
}
}
tmp.b = node.b;
if (cost > d[u][tmp.times][tmp.k][tmp.b]){
d[u][tmp.times][tmp.k][tmp.b] = cost;
if (!inq[tmp.u][tmp.times][tmp.k][tmp.b]){
inq[tmp.u][tmp.times][tmp.k][tmp.b] = 1;
que.push(tmp);
}
}
}
}
if (!flag) return -1;
int ans = 0;
for (int i = 0; i <= T; i++)
for (int j = 0; j <= B; j++)
ans = max(ans, d[n][i][0][j]);
return ans;
}
int kase;
void solve(){
scanf("%d%d%d%d%d%d", &n, &m, &B, &K, &R, &T);
memset(head, -1, sizeof(head));
tot = 0;
int u, v, tm, cost;
for (int i = 0; i < K; i++)
for (int j = 1; j <= n; j++) scanf("%d", &prices[i][j]);
for (int i = 0; i < m; i++){
scanf("%d%d%d%d", &u, &v, &tm, &cost);
addedge(u, v, tm, cost);
}
int ans = bfs();
printf("Case #%d: ", kase);
if (ans == -1) puts("Forever Alone");
else printf("%d\n", ans);
}
int main(){
int cs; scanf("%d", &cs);
for (kase = 1; kase <= cs; kase++) solve();
return 0;
}