题意很有意思,给了n段路,每段路长度不同,你有一辆车最多可以提供E的能量,你的车有四个档,最多换k次档
Assist Level 0 1 2 3
Assist Power 0 4 8 11
0档花费能量0,走的路程长度为0,1档花费1能量,走得最大路程为4.... ,每段路用一个档,如果这个档不能使你走完这段路,那么只能自己蹬,如果超过这段路长度,超过部分不计算到下一段路,意味着下一段路重算,问你蹬车的最短路程是多少
最多1000段路,最多换10次档,最大提供能量为50,那么最多的状态为1000*10*50*4 =2e6,搜索所有状态的话2m也够,但是在搜索过程中肯定会挂掉很多状态,这些状态到中途夭折,所以能走到第n段路的状态肯定小于2e6,所以可以广搜,由此总结,可以用状态表示的都可以进行搜索枚举出来,只要状态少,在时间允许内,一般1e6,
d[i][k][e][l]=cost ,表示走到底i段路剩余k次机会,剩余e能量用的事l档的最短蹬车路程。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
using namespace std;
const int maxn=1005,inf=0x3f3f3f3f;
int n,k,e;
int a[maxn];
int d[maxn][11][51][4],vis[maxn][11][51][4];
int pow[4]= {0,4,8,11};
int ans;
struct node
{
int pos,k,e,l;
};
void bfs()
{
queue<node>que;
memset(vis,0,sizeof(vis));
memset(d,inf,sizeof(d));
d[0][k][e][0]=0;
vis[0][k][e][0]=1;
node s;
s.pos=0;
s.k=k;
s.e=e;
s.l=0;
que.push(s);
int cost;
while(!que.empty())
{
node now=que.front();
que.pop();
int &cur=d[now.pos][now.k][now.e][now.l];
if(now.pos==n)
{
ans=min(cur,ans);
continue;
}
//vis[now.pos][now.k][now.e][now.l]=0;
if(now.k>0)
{
for(int i=0; i<4; i++)
{
if(i==now.l||now.e<i)///可用能量小于花费肯定不行,不换挡的情况后面讨论
continue;
node temp=now;
temp.pos++;
temp.k--;
temp.e-=i;
temp.l=i;
int &next=d[temp.pos][temp.k][temp.e][temp.l];
cost=max(0,a[temp.pos]-pow[temp.l]);
if(next>cur+cost)
{
next=cur+cost;
if(vis[temp.pos][temp.k][temp.e][temp.l]==0)
{
que.push(temp);
vis[temp.pos][temp.k][temp.e][temp.l]=1;
}
}
}
}
/// 不换挡,
node temp=now;
temp.pos++;
if(temp.e<temp.l)///能量不够了,直接变成0 挡,不用花费,直接蹬
temp.k=0, temp.e=0,temp.l=0;
else /// 能量足够,继续用此挡前行
temp.e-=temp.l;
cost=max(0,a[temp.pos]-pow[temp.l]);
int &next=d[temp.pos][temp.k][temp.e][temp.l];
if(next>cur+cost)
{
next=cur+cost;
if(vis[temp.pos][temp.k][temp.e][temp.l]==0)
{
que.push(temp);
vis[temp.pos][temp.k][temp.e][temp.l]=1;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
for(int cas=1; cas<=T; cas++)
{
scanf("%d%d%d",&n,&k,&e);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
ans=inf;
bfs();
printf("Case #%d: %d\n",cas,ans);
}
return 0;
}