题意非常长非常变态。一个人要到他男朋友家,他最初有R元以及T分钟的时间来赶到他男朋友家。有N个房子M条道路,每条道路有须要消耗的时间以及过路费,同一时候还要顺路做食盐生意,起初身上没有食盐,最多带B袋盐,每到达一个地方有三种操作能够选择:1.售出一袋食盐;2:购买一袋食盐;3:什么都不做。然后你以为结束了?不!它还存在平行宇宙,在一个城市能够选择穿越平行宇宙到达还有一个宇宙的这个城市,不同宇宙的食盐价格不同可是过路费和道路须要的时间是同样的,并且因为他是穿越党,他不能在别的宇宙回到自己家或者男朋友家,求最后是否能到达他男朋友家以及最多能有多少钱。

BFS+DP,由于时间是不可逆的,所以每次依照时间的先后来处理状态,因此须要用优先队列来处理。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <iomanip>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=111;
const int maxm=222;
struct Edge//邻接表
{
int v;
int tim;//时间花费
int cost;//金钱花费
int next;
};
struct Node
{
int u,times,k,b;
bool operator < (const Node &a) const
{
return times>a.times;
}
};
Edge edges[maxm<<1];
int head[maxn];
int num=-1;;
int n,m,B,K,R,T;
int dp[maxn][210][7][7];
int inqueue[maxn][210][7][7];
int price[7][maxn];
void addEdge(int u,int v,int tim,int cost)
{
num++;
edges[num].v=v;
edges[num].tim=tim;
edges[num].cost=cost;
edges[num].next=head[u];
head[u]=num;
}
int bfs()
{
int flag=0;
memset(dp,0,sizeof(dp));
memset(inqueue,0,sizeof(inqueue));
dp[1][0][0][0]=R;//初始金钱
Node node,tmp;
priority_queue<Node>q;//优先队列,按时间处理
node.u=1;//起始状态
node.times=0;
node.k=0;
node.b=0;
inqueue[1][0][0][0]=1;
q.push(node);
while(!q.empty())
{
node=q.top();
q.pop();
if(node.times>T)//当队里的元素的时间都大于T就无需处理了
{
break;
}
int u=node.u;
if(u==n)
{
//cout<<node.times<<endl;
continue;
}
for(int i=head[u];i!=-1;i=edges[i].next)//走到下一个城市
{
int v=edges[i].v;
int cost,tim;
cost=dp[u][node.times][node.k][node.b]-edges[i].cost;//剩下的金钱
tim=node.times+edges[i].tim;//时间
if(tim>T||cost<0)//剪枝
{
continue;
}
if(v==n&&node.k!=0)//仅仅能在0宇宙到达第N个城市
{
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-price[node.k][u]>dp[v][tim][node.k][node.b+1])//买一袋盐
{
dp[v][tim][node.k][node.b+1]=cost-price[node.k][u];
tmp.b=node.b+1;
if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
{
q.push(tmp);
inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
}
}
if(node.b>0&&cost+price[node.k][u]>dp[v][tim][node.k][node.b-1])//卖一袋盐
{
dp[v][tim][node.k][node.b-1]=cost+price[node.k][u];
tmp.b=node.b-1;
if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
{
q.push(tmp);
inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
}
}
}
if(cost>dp[v][tim][node.k][node.b])//不买盐
{
dp[v][tim][node.k][node.b]=cost;
tmp.b=node.b;
if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
{
q.push(tmp);
inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
}
}
}
if(u!=1&&u!=n)//穿越到下一个宇宙的这个城市
{
int cost=dp[u][node.times][node.k][node.b];//金钱不变
tmp.u=u;
tmp.k=(node.k+1)%K;
tmp.times=node.times+1;//看广告时间+1
if(tmp.times>T)
{
continue;
}
if(node.b+1<=B&&cost-price[node.k][u]>dp[u][tmp.times][tmp.k][node.b+1])//在这个宇宙的这个城市买盐
{
dp[u][tmp.times][tmp.k][node.b+1]=cost-price[node.k][u];
tmp.b=node.b+1;
if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
{
q.push(tmp);
inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
}
}
if(node.b>0&&cost+price[node.k][u]>dp[u][tmp.times][tmp.k][node.b-1])//卖一袋盐
{
dp[u][tmp.times][tmp.k][node.b-1]=cost+price[node.k][u];
tmp.b=node.b-1;
if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
{
q.push(tmp);
inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
}
}
tmp.b=node.b;
if(cost>dp[u][tmp.times][tmp.k][tmp.b])//不做操作
{
dp[u][tmp.times][tmp.k][tmp.b]=cost;
if(!inqueue[tmp.u][tmp.times][tmp.k][tmp.b])
{
q.push(tmp);
inqueue[tmp.u][tmp.times][tmp.k][tmp.b]=1;
}
}
}
}
if(!flag)
{
return -1;//不能到达
}
int ans=0;
for(int i=0;i<=T;i++)
{
for(int j=0;j<=B;j++)
{
ans=max(ans,dp[n][i][0][j]);//能够到达,在能够到的的情况中选取钱最多的
}
}
return ans;
}
int main()
{
int t;
int s=1;
int u,v,tim,cost;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d%d%d",&n,&m,&B,&K,&R,&T);//城市数目,道路数目,食盐上限,宇宙个数,初始金钱,时间上限
memset(head,-1,sizeof(head));
num=-1;
for(int i=0;i<K;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&price[i][j]);//食盐在每一个宇宙每一个城市的价格
}
}
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d",&u,&v,&tim,&cost);//每条路的起点,终点,时间,花费
addEdge(u,v,tim,cost);
}
int ans;
ans=bfs();
printf("Case #%d: ",s++);
if(ans!=-1)
{
printf("%d\n",ans);
}
else
{
printf("Forever Alone\n");
}
}
return 0;
}
04-30 03:01