题目大意:
一共有 n 个木桩,要求从起点(0)开始,经过所有梅花桩,恰好到达终点 n,尊者神高达一共会 k 种门派的轻功,不同门派的轻功经过的梅花桩数不同,花费时间也不同。但是尊者神高达一次只能使用一种轻功,当他使用别的门派的轻功时,需要花费 W 秒切换(开始时可以是任意门派,不需要更换时间)。由于尊者神高达手残,所以经过某些梅花桩(包括起点和终点)时他不能使用一些门派的轻功。尊者神高达想知道他最快多久能到达终点如果无解则输出-1。
思路:
很显然代价只和到第几个柱子和上次用的什么功法有关,然后跳的时候中间不能有特殊柱子,所以我们一开始预处理哪些点可以走,然后枚举柱子和功法直接dp就可以了。
程序:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int N=1005;
LL ans,n,k,W,a[N],w[N],q,x,p;
LL h[N][N],f[N][N];
int main(){
freopen("qinggong.in","r",stdin);
freopen("qinggong.out","w",stdout);
scanf("%lld%lld%lld",&n,&k,&W);
for (LL i=1;i<=k;i++) scanf("%lld%lld",&a[i],&w[i]);
scanf("%lld",&q);
for (LL i=1;i<=q;i++) {
scanf("%lld%lld",&x,&p);
h[x][p]=1;
for (LL j=1;j<=a[p];j++) h[x+j][p]=1;
}
memset(f,31,sizeof(f));
for (LL i=1;i<=k;i++) f[0][i]=0;
for (LL i=1;i<=n;i++)
for (LL j=1;j<=k;j++)
if (!h[i][j]){
for (LL ii=1;ii<=k;ii++)
if (ii==j&&i-a[j]>=0) f[i][j]=min(f[i][j],f[i-a[j]][ii]+w[j]);
else if (i-a[j]>=0) f[i][j]=min(f[i][j],f[i-a[j]][ii]+w[j]+W);
}
ans=12345678900;
for (LL i=1;i<=k;i++) ans=min(ans,f[n][i]);
if (ans==12345678900) printf("-1");
else printf("%lld",ans);
}