在k个平行空间中,n个点,由m条有向边连接起来,每条边有一个时间花费和金钱花费,同时,在每个点上,可以跳转到(ki+1)%k 的空间里,不同空间的边权值不变。另外,在每到达某个空间的某个顶点时,可以买一包盐,卖一包盐,或者什么也不做,买卖的时间不考虑。相同的顶点在不同的空间中盐的价格也不一定相同..现在给定顶点数n,边数m,盐的最大携带量b,空间数k,初始的金钱r,规定的时间t,问怎么走可以在t时间内从1到达n,并且使到达n时身上的金钱尽可能大。初始时身上一包盐也没有,并且只有在空间0的时候,才能访问顶点1和n,并且一旦到达顶点n,这个过程就要结束……
很绕口的题目= =….读清楚题意的话首先很容易想到spfa..现场赛的时候估计时间空间给的比较宽松,的确有队伍用spfa过了,但也有被卡常数的..hdoj上spfa估计就不太好过了..时间卡的太近。我是直接写了一个bfs,记录dp【id】【b】【k】【t】,表示在顶点id,身上有b包盐,空间k,还剩t分钟的时间时,身上最多能有多少钱,刚开始写spfa,需要反复的进出队列,所以很悲剧的TLE了。要控制每个状态进出队列一次,又发现有些状态明明可以取得一个更大的值-,但它之前已经被一个小的值占用了-然后我就直接把队列换成了个优先队列,按剩余时间的大小从大到下向下扩展状态,这样就可以保证bfs进行的时候,一定是按时间来一层一层扩展的,并且可以保证在从当前状态开始扩展之前,当前的状态一定是最优的。另外还有一个小坑-不知道是我别的地方写毁了还是怎么回事-..每次跳转空间或者是走到新的顶点时,如果目标点的dp值需要更新,显然需要根据更新后的值来扩展买,卖,不买不卖三种新的状态,但是如果目标点的值不需要更新,我依然需要按这个“不是目标状态最优的值”来扩展买,卖,不买不卖三种状态。举个例子
当前状态如果是2 2 0 25 下一步可以到达 2 2 1 24 然后卖掉一包盐扩展出 2 1 1 24,因为已经卖了一包盐了,他不可以再扩展出2 0 1 24.然后到达2 1 0 25的时候,下一步到达2 1 1 24发现这么走到2 1 1 24没有它当前的钱多,但这个不是最优的状态却可以继续扩展出2 0 1 24这个状态的最优值,所以在这就算得到的不是最优的钱数,我们依然需要往下扩展一下…然后就AC了……
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
bool vis[105][6][6][202];
int g[105][6][6][202];
int n,m,b,r,k,t,numtt;
int trade[105][6];
inline int getint() {
char c = getchar();
int t = 0;
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {
t = t * 10 + c - '0';
c = getchar();
}
return t;
}
struct Edge
{
int v,wt,wm,next;
}edge[202];
int ge[105];
struct sta
{
int id,b,k,t;
sta(){};
sta(int x1,int x2,int x3,int x4)
{
id=x1;
b=x2;
k=x3;
t=x4;
}
// bool operator>(const sta& s1)const
// {
//
// return t>s1.t;
// }
bool operator<(const sta& s1)const
{
return t q;
vis[1][0][0][t]=true;
g[1][0][0][t]=r;
q.push(sta(1,0,0,t));
while(!q.empty())
{
sta now=q.top();
sta tmp=now;
q.pop();
// vis[now.id][now.b][now.k][now.t]=false;
int tid=now.id,tb=now.b,tk=now.k,tt=now.t;
int fee;
if (tt>0 && tid!=n && tid!=1)
{
tk++;
if (tk==k) tk=0;
tt--;
if (g[tid][tb][tk][tt]=trade[ttid][ttk] && ttb0)
{
fee+=trade[ttid][ttk];
ttb--;
if (g[ttid][ttb][ttk][ttt]=edge[j].wm && tt>=edge[j].wt)
{
v=edge[j].v;
if ((v==1 || v==n) && tk!=0) continue;
fee-=edge[j].wm;
tt-=edge[j].wt;
if (g[v][tb][tk][tt]=trade[v][tk] && ttb0)
{
fee+=trade[v][tk];
ttb--;
if (g[v][ttb][ttk][ttt]=0) printf("%d\n",ans);
else puts("Forever Alone");
}
return 0;
}