LA 6538 Dinner Coming Soon DP
2015-10-26 20:40
465 查看
题意:
给出一个有\(N\)个顶点\(M\)条有向边的图,起点为\(1\),终点为\(N\)。每条边有经过的时间,和经过这条边的花费。一开始你有\(R\)元钱,要在\(T\)时间内赶到终点去约会。
每次到一个顶点(起点和终点除外),该顶点标好了价格,你可以:
在这里购买一袋盐
在这里出售一袋盐
或者什么都不做
在整个交易的过程中你的钱不能是负数,你身上携带的盐不能超过\(B\)袋。
更要命的是,你还有个手持电子设备,你可以在\(K\)个平行时空中穿梭,你本来所在的平行时空的编号为\(0\)。
具体来说就是,花费\(1\)单位时间,你可以从第\(i\)个平行时空穿越到第\((i+1)%K\)个平行时空。
所有平行时空的地图一样,每条边花费的时间以及费用也一样,但是每个点交易盐的价格会有变化。
为了避免一起混乱,你只能到自己原来所在的平行时空的点\(1\)和\(N\)。
求可以及时赶到约会地点的前提下,最多能赚多少钱。
分析:
这题可以用\(DP\)来做,设计一个状态:\(d(t, dim, u, b, c)\)表示正在第\(dim\)个平行时空的\(u\)顶点花费了\(t\)时间,身上有\(b\)袋盐,\(c=0\)表示还没有进行交易,\(c=1\)表示已经进行过交易了,所能得到的最多的钱。那么有下面几种决策:
我们可以在该平行时空下往前走到\(v\)点,转移的条件是身上的钱足够支付路费和走这条边的时间不会超过总时间。
可以花费\(1\)个单位时间传送到下一个平行时空,转移的条件是不会超出限制时间。
我们可以在这买一袋盐,转移条件是身上的钱足够而且之前没有进行过交易
我们还可以卖一袋盐,转移条件是身上至少携带一袋盐而且之前没有进行过交易
代码是用递推的方式写的,但要注意循环顺序。
最后说一下为什么可以\(DP\),其实就是时间一直是递增的,只会有之前的时间的状态更新之后时间的状态。
更详细的说明可以参考这里
#include <cstdio> #include <cstring> #include <algorithm> #define REP(i, n) for(int i = 0; i < (n); i++) using namespace std; void update(int& a, int b) { if(b > a) a = b; } const int maxn = 100 + 10; const int maxm = 200 + 10; struct Edge { int v, dist, cost, nxt; Edge() {} Edge(int v, int d, int c, int nxt):v(v), dist(d), cost(c), nxt(nxt) {} }; int ecnt; Edge edges[maxm]; int head[maxn], nxt[maxm]; void init() { memset(head, -1, sizeof(head)); ecnt = 0; } void AddEdge(int u, int v, int dist, int cost) { edges[ecnt] = Edge(v, dist, cost, head[u]); head[u] = ecnt++; } int N, M, B, K, R, T; int price[10][maxn]; int d[210][7][110][7][2]; int main() { //freopen("6538.txt", "r", stdin); int Test; scanf("%d", &Test); for(int kase = 1; kase <= Test; kase++) { init(); scanf("%d%d%d%d%d%d", &N, &M, &B, &K, &R, &T); REP(i, K) REP(j, N) scanf("%d", &price[i][j]); REP(i, M) { int u, v, t, m; scanf("%d%d%d%d", &u, &v, &t, &m); u--; v--; AddEdge(u, v, t, m); } //DP memset(d, -1, sizeof(d)); d[0][0][0][0][0] = R; int ans = -1; REP(t, T+1) REP(dim, K) REP(u, N) REP(c, 2) REP(b, B+1) { int& cur = d[t][dim][u][b][c]; if(cur == -1) continue; if(dim == 0 && u == N-1) { update(ans, cur); continue; } //printf("t = %d, dim = %d, u = %d, b = %d, c = %d, cur = %d\n", t, dim, u, b, c, cur); for(int i = head[u]; ~i; i = edges[i].nxt) { Edge& e = edges[i]; if(dim != 0 && (e.v == 0 || e.v == N-1)) continue; if(t + e.dist <= T && cur >= e.cost) update(d[t + e.dist][dim][e.v][b][0], cur - e.cost); } if(t + 1 <= T && u != 0 && u != N-1) update(d[t + 1][(dim+1) % K][u][b][0], cur); if(c == 0) { if(u == 0 || u == N-1) continue; if(cur >= price[dim][u] && b < B) update(d[t][dim][u][b+1][1], cur - price[dim][u]); if(b) update(d[t][dim][u][b-1][1], cur + price[dim][u]); } } printf("Case #%d: ", kase); if(ans == -1) printf("Forever Alone\n"); else printf("%d\n", ans); } return 0; }
相关文章推荐
- android开发之shape详解
- Depth-First-Search(DFS伪代码)
- android开发之shape详解
- android开发之shape详解
- 对架构是怎样的理解
- 黑马程序员——C语言基础---结构体
- 蛮力算法: 选择排序 冒泡排序(详解)
- ural 1286. Starship Travel
- 信息安全系统设计基础第六周学习总结
- android开发之shape详解
- Jquery+div+css实现弹出登录窗口
- android关于popupWindow不显示
- ZOJ 2830
- InnoDB事务的开启
- Canvas画板实现一个简单的球在盒子内随机移动效果
- poj 2155 (二维数组)
- 基于的DCT水印算法实现
- IOS开发笔记10-字符串-C语言笔记
- 实战iOS7之NSURLSession
- Eclipse、IDEA环境下设置jvm默认编码