题目大意:
题目链接:https://jzoj.net/senior/#main/show/5907
题目图片:
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fwqa674nrcj30jb0e93z2.jpg
http://wx1.sinaimg.cn/mw690/0060lm7Tly1fwqa674c41j30ja0ctjrl.jpg
http://wx2.sinaimg.cn/mw690/0060lm7Tly1fwqa6743zij30jf0ardfv.jpg
有个木桩和种轻功,第种轻功要花费的时间往前个梅花桩。有些轻功不可以经过(含从上面飞过)一些木桩。求从到的最小时间。切换轻功需要的时间。
思路:
很明显是。
设表示跳到第个梅花桩,准备用轻功跳下一个梅花桩的最小时间花费。
那么很明显我们要枚举是用哪一个轻功飞到第个梅花桩的。那么再在第三重循环枚举。
那么如果,就不用花费去切换,就有:
如果,那么久在后面加一个即可。
答案就是
时间复杂度,常数不是很大,可以过掉。
代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#define ll long long
#define N 510
#define M 110
using namespace std;
int n,m,s,q;
bool p[N][M];
ll f[N][M];
struct node
{
int t,f;
}a[N];
bool check(int l,int r,int x) //判断飞过的梅花桩中是否有不允许用这种轻功过的
{
for (int i=l;i<=r;i++)
if (p[i][x]==1) return 0;
return 1;
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for (int i=1;i<=m;i++)
scanf("%d%d",&a[i].f,&a[i].t);
scanf("%d",&q);
int x,y;
for (int i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
p[x][y]=1;
}
for (int i=0;i<=n;i++)
for (int j=1;j<=m;j++)
f[i][j]=1e17;
for (int i=1;i<=m;i++)
if (!p[0][i])
f[0][i]=0; //初始化
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (i-a[j].f>=0&&check(i-a[j].f,i,j))
for (int k=1;k<=m;k++)
if (j!=k)
f[i][j]=min(f[i][j],f[i-a[j].f][k]+(ll)a[j].t+(ll)s);
else
f[i][j]=min(f[i][j],f[i-a[j].f][k]+(ll)a[j].t);
ll ans=1e17;
for (int i=1;i<=m;i++)
if (!p[n][i])
ans=min(ans,f[n][i]);
if (ans<1e17) cout<<ans;
else printf("-1");
return 0;
}